Fri, 11 Apr 2008 09:56:35 -0400
Merge
1.1 --- a/.hgignore Thu Apr 10 15:49:16 2008 -0400 1.2 +++ b/.hgignore Fri Apr 11 09:56:35 2008 -0400 1.3 @@ -1,3 +1,4 @@ 1.4 ^build/ 1.5 ^dist/ 1.6 ^nbproject/private/ 1.7 +^src/share/tools/hsdis/bin/
2.1 --- a/make/linux/makefiles/vm.make Thu Apr 10 15:49:16 2008 -0400 2.2 +++ b/make/linux/makefiles/vm.make Fri Apr 11 09:56:35 2008 -0400 2.3 @@ -71,6 +71,7 @@ 2.4 # The following variables are defined in the generated flags.make file. 2.5 BUILD_VERSION = -DHOTSPOT_RELEASE_VERSION="\"$(HS_BUILD_VER)\"" 2.6 JRE_VERSION = -DJRE_RELEASE_VERSION="\"$(JRE_RELEASE_VER)\"" 2.7 +HS_LIB_ARCH = -DHOTSPOT_LIB_ARCH=\"$(LIBARCH)\" 2.8 BUILD_TARGET = -DHOTSPOT_BUILD_TARGET="\"$(TARGET)\"" 2.9 BUILD_USER = -DHOTSPOT_BUILD_USER="\"$(HOTSPOT_BUILD_USER)\"" 2.10 VM_DISTRO = -DHOTSPOT_VM_DISTRO="\"$(HOTSPOT_VM_DISTRO)\"" 2.11 @@ -81,6 +82,7 @@ 2.12 ${BUILD_VERSION} \ 2.13 ${BUILD_TARGET} \ 2.14 ${BUILD_USER} \ 2.15 + ${HS_LIB_ARCH} \ 2.16 ${JRE_VERSION} \ 2.17 ${VM_DISTRO} 2.18
3.1 --- a/make/linux/platform_amd64 Thu Apr 10 15:49:16 2008 -0400 3.2 +++ b/make/linux/platform_amd64 Fri Apr 11 09:56:35 2008 -0400 3.3 @@ -12,6 +12,4 @@ 3.4 3.5 compiler = gcc 3.6 3.7 -gnu_dis_arch = amd64 3.8 - 3.9 sysdefs = -DLINUX -D_GNU_SOURCE -DAMD64
4.1 --- a/make/linux/platform_i486 Thu Apr 10 15:49:16 2008 -0400 4.2 +++ b/make/linux/platform_i486 Fri Apr 11 09:56:35 2008 -0400 4.3 @@ -12,6 +12,4 @@ 4.4 4.5 compiler = gcc 4.6 4.7 -gnu_dis_arch = i386 4.8 - 4.9 sysdefs = -DLINUX -D_GNU_SOURCE -DIA32
5.1 --- a/make/linux/platform_sparc Thu Apr 10 15:49:16 2008 -0400 5.2 +++ b/make/linux/platform_sparc Fri Apr 11 09:56:35 2008 -0400 5.3 @@ -12,6 +12,4 @@ 5.4 5.5 compiler = gcc 5.6 5.7 -gnu_dis_arch = sparc 5.8 - 5.9 sysdefs = -DLINUX -D_GNU_SOURCE -DSPARC
6.1 --- a/make/solaris/makefiles/vm.make Thu Apr 10 15:49:16 2008 -0400 6.2 +++ b/make/solaris/makefiles/vm.make Fri Apr 11 09:56:35 2008 -0400 6.3 @@ -63,6 +63,7 @@ 6.4 # The following variables are defined in the generated flags.make file. 6.5 BUILD_VERSION = -DHOTSPOT_RELEASE_VERSION="\"$(HS_BUILD_VER)\"" 6.6 JRE_VERSION = -DJRE_RELEASE_VERSION="\"$(JRE_RELEASE_VER)\"" 6.7 +HS_LIB_ARCH = -DHOTSPOT_LIB_ARCH=\"$(LIBARCH)\" 6.8 BUILD_TARGET = -DHOTSPOT_BUILD_TARGET="\"$(TARGET)\"" 6.9 BUILD_USER = -DHOTSPOT_BUILD_USER="\"$(HOTSPOT_BUILD_USER)\"" 6.10 VM_DISTRO = -DHOTSPOT_VM_DISTRO="\"$(HOTSPOT_VM_DISTRO)\"" 6.11 @@ -73,6 +74,7 @@ 6.12 ${BUILD_VERSION} \ 6.13 ${BUILD_TARGET} \ 6.14 ${BUILD_USER} \ 6.15 + ${HS_LIB_ARCH} \ 6.16 ${JRE_VERSION} \ 6.17 ${VM_DISTRO} 6.18
7.1 --- a/make/solaris/platform_amd64 Thu Apr 10 15:49:16 2008 -0400 7.2 +++ b/make/solaris/platform_amd64 Fri Apr 11 09:56:35 2008 -0400 7.3 @@ -12,6 +12,4 @@ 7.4 7.5 compiler = sparcWorks 7.6 7.7 -gnu_dis_arch = amd64 7.8 - 7.9 sysdefs = -DSOLARIS -DSPARC_WORKS -DAMD64
8.1 --- a/make/solaris/platform_amd64.gcc Thu Apr 10 15:49:16 2008 -0400 8.2 +++ b/make/solaris/platform_amd64.gcc Fri Apr 11 09:56:35 2008 -0400 8.3 @@ -12,6 +12,4 @@ 8.4 8.5 compiler = gcc 8.6 8.7 -gnu_dis_arch = amd64 8.8 - 8.9 sysdefs = -DSOLARIS -D_GNU_SOURCE -DAMD64
9.1 --- a/make/solaris/platform_i486 Thu Apr 10 15:49:16 2008 -0400 9.2 +++ b/make/solaris/platform_i486 Fri Apr 11 09:56:35 2008 -0400 9.3 @@ -12,6 +12,4 @@ 9.4 9.5 compiler = sparcWorks 9.6 9.7 -gnu_dis_arch = i386 9.8 - 9.9 sysdefs = -DSOLARIS -DSPARC_WORKS -DIA32
10.1 --- a/make/solaris/platform_i486.gcc Thu Apr 10 15:49:16 2008 -0400 10.2 +++ b/make/solaris/platform_i486.gcc Fri Apr 11 09:56:35 2008 -0400 10.3 @@ -12,6 +12,4 @@ 10.4 10.5 compiler = gcc 10.6 10.7 -gnu_dis_arch = i386 10.8 - 10.9 sysdefs = -DSOLARIS -D_GNU_SOURCE -DIA32
11.1 --- a/make/solaris/platform_sparc Thu Apr 10 15:49:16 2008 -0400 11.2 +++ b/make/solaris/platform_sparc Fri Apr 11 09:56:35 2008 -0400 11.3 @@ -12,6 +12,4 @@ 11.4 11.5 compiler = sparcWorks 11.6 11.7 -gnu_dis_arch = sparc 11.8 - 11.9 sysdefs = -DSOLARIS -DSPARC_WORKS -DSPARC
12.1 --- a/make/solaris/platform_sparc.gcc Thu Apr 10 15:49:16 2008 -0400 12.2 +++ b/make/solaris/platform_sparc.gcc Fri Apr 11 09:56:35 2008 -0400 12.3 @@ -12,6 +12,4 @@ 12.4 12.5 compiler = gcc 12.6 12.7 -gnu_dis_arch = sparc 12.8 - 12.9 sysdefs = -DSOLARIS -D_GNU_SOURCE -DSPARC
13.1 --- a/make/solaris/platform_sparcv9 Thu Apr 10 15:49:16 2008 -0400 13.2 +++ b/make/solaris/platform_sparcv9 Fri Apr 11 09:56:35 2008 -0400 13.3 @@ -8,10 +8,8 @@ 13.4 13.5 os_arch_model = solaris_sparc 13.6 13.7 -lib_arch = sparc 13.8 +lib_arch = sparcv9 13.9 13.10 compiler = sparcWorks 13.11 13.12 -gnu_dis_arch = sparc 13.13 - 13.14 sysdefs = -DSOLARIS -DSPARC_WORKS -DSPARC
14.1 --- a/make/solaris/platform_sparcv9.gcc Thu Apr 10 15:49:16 2008 -0400 14.2 +++ b/make/solaris/platform_sparcv9.gcc Fri Apr 11 09:56:35 2008 -0400 14.3 @@ -8,10 +8,8 @@ 14.4 14.5 os_arch_model = solaris_sparc 14.6 14.7 -lib_arch = sparc 14.8 +lib_arch = sparcv9 14.9 14.10 compiler = gcc 14.11 14.12 -gnu_dis_arch = sparc 14.13 - 14.14 sysdefs = -DSOLARIS -D_GNU_SOURCE -DSPARC
15.1 --- a/make/windows/makefiles/vm.make Thu Apr 10 15:49:16 2008 -0400 15.2 +++ b/make/windows/makefiles/vm.make Fri Apr 11 09:56:35 2008 -0400 15.3 @@ -58,6 +58,7 @@ 15.4 # The following variables are defined in the generated local.make file. 15.5 CPP_FLAGS=$(CPP_FLAGS) /D "HOTSPOT_RELEASE_VERSION=\"$(HS_BUILD_VER)\"" 15.6 CPP_FLAGS=$(CPP_FLAGS) /D "JRE_RELEASE_VERSION=\"$(JRE_RELEASE_VER)\"" 15.7 +CPP_FLAGS=$(CPP_FLAGS) /D "HOTSPOT_LIB_ARCH=\"$(BUILDARCH)\"" 15.8 CPP_FLAGS=$(CPP_FLAGS) /D "HOTSPOT_BUILD_TARGET=\"$(BUILD_FLAVOR)\"" 15.9 CPP_FLAGS=$(CPP_FLAGS) /D "HOTSPOT_BUILD_USER=\"$(BuildUser)\"" 15.10 CPP_FLAGS=$(CPP_FLAGS) /D "HOTSPOT_VM_DISTRO=\"$(HOTSPOT_VM_DISTRO)\""
16.1 --- a/make/windows/platform_amd64 Thu Apr 10 15:49:16 2008 -0400 16.2 +++ b/make/windows/platform_amd64 Fri Apr 11 09:56:35 2008 -0400 16.3 @@ -10,6 +10,6 @@ 16.4 16.5 os_arch_model = windows_x86_64 16.6 16.7 +lib_arch = amd64 16.8 + 16.9 compiler = visCPP 16.10 - 16.11 -gnu_dis_arch = amd64
17.1 --- a/make/windows/platform_i486 Thu Apr 10 15:49:16 2008 -0400 17.2 +++ b/make/windows/platform_i486 Fri Apr 11 09:56:35 2008 -0400 17.3 @@ -10,7 +10,6 @@ 17.4 17.5 os_arch_model = windows_x86_32 17.6 17.7 +lib_arch = i386 17.8 + 17.9 compiler = visCPP 17.10 - 17.11 -gnu_dis_arch = i386 17.12 -
18.1 --- a/src/cpu/sparc/vm/disassembler_sparc.cpp Thu Apr 10 15:49:16 2008 -0400 18.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 18.3 @@ -1,230 +0,0 @@ 18.4 -/* 18.5 - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. 18.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 18.7 - * 18.8 - * This code is free software; you can redistribute it and/or modify it 18.9 - * under the terms of the GNU General Public License version 2 only, as 18.10 - * published by the Free Software Foundation. 18.11 - * 18.12 - * This code is distributed in the hope that it will be useful, but WITHOUT 18.13 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 18.14 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18.15 - * version 2 for more details (a copy is included in the LICENSE file that 18.16 - * accompanied this code). 18.17 - * 18.18 - * You should have received a copy of the GNU General Public License version 18.19 - * 2 along with this work; if not, write to the Free Software Foundation, 18.20 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18.21 - * 18.22 - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 18.23 - * CA 95054 USA or visit www.sun.com if you need additional information or 18.24 - * have any questions. 18.25 - * 18.26 - */ 18.27 - 18.28 -# include "incls/_precompiled.incl" 18.29 -# include "incls/_disassembler_sparc.cpp.incl" 18.30 - 18.31 -#ifndef PRODUCT 18.32 - 18.33 -#define SPARC_VERSION (VM_Version::v9_instructions_work()? \ 18.34 - (VM_Version::v8_instructions_work()? "" : "9") : "8") 18.35 - 18.36 -// This routine is in the shared library: 18.37 -typedef unsigned char* print_insn_sparc_t(unsigned char* start, DisassemblerEnv* env, 18.38 - const char* sparc_version); 18.39 - 18.40 -void* Disassembler::_library = NULL; 18.41 -dll_func Disassembler::_print_insn_sparc = NULL; 18.42 - 18.43 -bool Disassembler::load_library() { 18.44 - if (_library == NULL) { 18.45 - char buf[1024]; 18.46 - char ebuf[1024]; 18.47 - sprintf(buf, "disassembler%s", os::dll_file_extension()); 18.48 - _library = hpi::dll_load(buf, ebuf, sizeof ebuf); 18.49 - if (_library != NULL) { 18.50 - tty->print_cr("Loaded disassembler"); 18.51 - _print_insn_sparc = CAST_TO_FN_PTR(dll_func, hpi::dll_lookup(_library, "print_insn_sparc")); 18.52 - } 18.53 - } 18.54 - return (_library != NULL) && (_print_insn_sparc != NULL); 18.55 -} 18.56 - 18.57 - 18.58 -class sparc_env : public DisassemblerEnv { 18.59 - private: 18.60 - nmethod* code; 18.61 - outputStream* output; 18.62 - const char* version; 18.63 - 18.64 - static void print_address(address value, outputStream* st); 18.65 - 18.66 - public: 18.67 - sparc_env(nmethod* rcode, outputStream* routput) { 18.68 - code = rcode; 18.69 - output = routput; 18.70 - version = SPARC_VERSION; 18.71 - } 18.72 - const char* sparc_version() { return version; } 18.73 - void print_label(intptr_t value); 18.74 - void print_raw(char* str) { output->print_raw(str); } 18.75 - void print(char* format, ...); 18.76 - char* string_for_offset(intptr_t value); 18.77 - char* string_for_constant(unsigned char* pc, intptr_t value, int is_decimal); 18.78 -}; 18.79 - 18.80 - 18.81 -void sparc_env::print_address(address adr, outputStream* st) { 18.82 - if (!Universe::is_fully_initialized()) { 18.83 - st->print(INTPTR_FORMAT, (intptr_t)adr); 18.84 - return; 18.85 - } 18.86 - if (StubRoutines::contains(adr)) { 18.87 - StubCodeDesc *desc = StubCodeDesc::desc_for(adr); 18.88 - if (desc == NULL) 18.89 - desc = StubCodeDesc::desc_for(adr + frame::pc_return_offset); 18.90 - if (desc == NULL) 18.91 - st->print("Unknown stub at " INTPTR_FORMAT, adr); 18.92 - else { 18.93 - st->print("Stub::%s", desc->name()); 18.94 - if (desc->begin() != adr) 18.95 - st->print("%+d 0x%p",adr - desc->begin(), adr); 18.96 - else if (WizardMode) st->print(" " INTPTR_FORMAT, adr); 18.97 - } 18.98 - } else { 18.99 - BarrierSet* bs = Universe::heap()->barrier_set(); 18.100 - if (bs->kind() == BarrierSet::CardTableModRef && 18.101 - adr == (address)((CardTableModRefBS*)(bs))->byte_map_base) { 18.102 - st->print("word_map_base"); 18.103 - if (WizardMode) st->print(" " INTPTR_FORMAT, (intptr_t)adr); 18.104 - } else { 18.105 - st->print(INTPTR_FORMAT, (intptr_t)adr); 18.106 - } 18.107 - } 18.108 -} 18.109 - 18.110 - 18.111 -// called by the disassembler to print out jump addresses 18.112 -void sparc_env::print_label(intptr_t value) { 18.113 - print_address((address) value, output); 18.114 -} 18.115 - 18.116 -void sparc_env::print(char* format, ...) { 18.117 - va_list ap; 18.118 - va_start(ap, format); 18.119 - output->vprint(format, ap); 18.120 - va_end(ap); 18.121 -} 18.122 - 18.123 -char* sparc_env::string_for_offset(intptr_t value) { 18.124 - stringStream st; 18.125 - print_address((address) value, &st); 18.126 - return st.as_string(); 18.127 -} 18.128 - 18.129 -char* sparc_env::string_for_constant(unsigned char* pc, intptr_t value, int is_decimal) { 18.130 - stringStream st; 18.131 - oop obj; 18.132 - if (code && (obj = code->embeddedOop_at(pc)) != NULL) { 18.133 - obj->print_value_on(&st); 18.134 - } else 18.135 - { 18.136 - print_address((address) value, &st); 18.137 - } 18.138 - return st.as_string(); 18.139 -} 18.140 - 18.141 - 18.142 -address Disassembler::decode_instruction(address start, DisassemblerEnv* env) { 18.143 - const char* version = ((sparc_env*)env)->sparc_version(); 18.144 - return ((print_insn_sparc_t*) _print_insn_sparc)(start, env, version); 18.145 -} 18.146 - 18.147 - 18.148 -const int show_bytes = false; // for disassembler debugging 18.149 - 18.150 - 18.151 -void Disassembler::decode(CodeBlob* cb, outputStream* st) { 18.152 - st = st ? st : tty; 18.153 - st->print_cr("Decoding CodeBlob " INTPTR_FORMAT, cb); 18.154 - decode(cb->instructions_begin(), cb->instructions_end(), st); 18.155 -} 18.156 - 18.157 - 18.158 -void Disassembler::decode(u_char* begin, u_char* end, outputStream* st) { 18.159 - assert ((((intptr_t)begin | (intptr_t)end) % sizeof(int) == 0), "misaligned insn addr"); 18.160 - st = st ? st : tty; 18.161 - if (!load_library()) { 18.162 - st->print_cr("Could not load disassembler"); 18.163 - return; 18.164 - } 18.165 - sparc_env env(NULL, st); 18.166 - unsigned char* p = (unsigned char*) begin; 18.167 - CodeBlob* cb = CodeCache::find_blob_unsafe(begin); 18.168 - while (p < (unsigned char*) end && p) { 18.169 - if (cb != NULL) { 18.170 - cb->print_block_comment(st, (intptr_t)(p - cb->instructions_begin())); 18.171 - } 18.172 - 18.173 - unsigned char* p0 = p; 18.174 - st->print(INTPTR_FORMAT ": ", p); 18.175 - p = decode_instruction(p, &env); 18.176 - if (show_bytes && p) { 18.177 - st->print("\t\t\t"); 18.178 - while (p0 < p) { st->print("%08lx ", *(int*)p0); p0 += sizeof(int); } 18.179 - } 18.180 - st->cr(); 18.181 - } 18.182 -} 18.183 - 18.184 - 18.185 -void Disassembler::decode(nmethod* nm, outputStream* st) { 18.186 - st = st ? st : tty; 18.187 - 18.188 - st->print_cr("Decoding compiled method " INTPTR_FORMAT ":", nm); 18.189 - st->print("Code:"); 18.190 - st->cr(); 18.191 - 18.192 - if (!load_library()) { 18.193 - st->print_cr("Could not load disassembler"); 18.194 - return; 18.195 - } 18.196 - sparc_env env(nm, st); 18.197 - unsigned char* p = nm->instructions_begin(); 18.198 - unsigned char* end = nm->instructions_end(); 18.199 - assert ((((intptr_t)p | (intptr_t)end) % sizeof(int) == 0), "misaligned insn addr"); 18.200 - 18.201 - unsigned char *p1 = p; 18.202 - int total_bucket_count = 0; 18.203 - while (p1 < end && p1) { 18.204 - unsigned char *p0 = p1; 18.205 - ++p1; 18.206 - address bucket_pc = FlatProfiler::bucket_start_for(p1); 18.207 - if (bucket_pc != NULL && bucket_pc > p0 && bucket_pc <= p1) 18.208 - total_bucket_count += FlatProfiler::bucket_count_for(p0); 18.209 - } 18.210 - 18.211 - while (p < end && p) { 18.212 - if (p == nm->entry_point()) st->print_cr("[Entry Point]"); 18.213 - if (p == nm->verified_entry_point()) st->print_cr("[Verified Entry Point]"); 18.214 - if (p == nm->exception_begin()) st->print_cr("[Exception Handler]"); 18.215 - if (p == nm->stub_begin()) st->print_cr("[Stub Code]"); 18.216 - if (p == nm->consts_begin()) st->print_cr("[Constants]"); 18.217 - nm->print_block_comment(st, (intptr_t)(p - nm->instructions_begin())); 18.218 - unsigned char* p0 = p; 18.219 - st->print(" " INTPTR_FORMAT ": ", p); 18.220 - p = decode_instruction(p, &env); 18.221 - nm->print_code_comment_on(st, 40, p0, p); 18.222 - st->cr(); 18.223 - // Output pc bucket ticks if we have any 18.224 - address bucket_pc = FlatProfiler::bucket_start_for(p); 18.225 - if (bucket_pc != NULL && bucket_pc > p0 && bucket_pc <= p) { 18.226 - int bucket_count = FlatProfiler::bucket_count_for(p0); 18.227 - tty->print_cr("%3.1f%% [%d]", bucket_count*100.0/total_bucket_count, bucket_count); 18.228 - tty->cr(); 18.229 - } 18.230 - } 18.231 -} 18.232 - 18.233 -#endif // PRODUCT
19.1 --- a/src/cpu/sparc/vm/disassembler_sparc.hpp Thu Apr 10 15:49:16 2008 -0400 19.2 +++ b/src/cpu/sparc/vm/disassembler_sparc.hpp Fri Apr 11 09:56:35 2008 -0400 19.3 @@ -1,5 +1,5 @@ 19.4 /* 19.5 - * Copyright 1997-1999 Sun Microsystems, Inc. All Rights Reserved. 19.6 + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. 19.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 19.8 * 19.9 * This code is free software; you can redistribute it and/or modify it 19.10 @@ -22,30 +22,11 @@ 19.11 * 19.12 */ 19.13 19.14 -// The disassembler prints out sparc code annotated 19.15 -// with Java specific information. 19.16 + static int pd_instruction_alignment() { 19.17 + return sizeof(int); 19.18 + } 19.19 19.20 -class Disassembler { 19.21 -#ifndef PRODUCT 19.22 - private: 19.23 - // points to the library. 19.24 - static void* _library; 19.25 - // points to the print_insn_sparc function. 19.26 - static dll_func _print_insn_sparc; 19.27 - // tries to load library and return whether it succedded. 19.28 - static bool load_library(); 19.29 - // decodes one instruction and return the start of the next instruction. 19.30 - static address decode_instruction(address start, DisassemblerEnv* env); 19.31 -#endif 19.32 - public: 19.33 - static void decode(CodeBlob *cb, outputStream* st = NULL) PRODUCT_RETURN; 19.34 - static void decode(nmethod* nm, outputStream* st = NULL) PRODUCT_RETURN; 19.35 - static void decode(u_char* begin, u_char* end, outputStream* st = NULL) PRODUCT_RETURN; 19.36 -}; 19.37 - 19.38 -//Reconciliation History 19.39 -// 1.9 98/04/29 10:45:51 disassembler_i486.hpp 19.40 -// 1.10 98/05/11 16:47:20 disassembler_i486.hpp 19.41 -// 1.12 99/06/22 16:37:37 disassembler_i486.hpp 19.42 -// 1.13 99/08/06 10:09:04 disassembler_i486.hpp 19.43 -//End 19.44 + static const char* pd_cpu_opts() { 19.45 + return (VM_Version::v9_instructions_work()? 19.46 + (VM_Version::v8_instructions_work()? "" : "v9only") : "v8only"); 19.47 + }
20.1 --- a/src/cpu/sparc/vm/frame_sparc.cpp Thu Apr 10 15:49:16 2008 -0400 20.2 +++ b/src/cpu/sparc/vm/frame_sparc.cpp Fri Apr 11 09:56:35 2008 -0400 20.3 @@ -157,22 +157,158 @@ 20.4 check_location_valid(); 20.5 } 20.6 20.7 +bool frame::safe_for_sender(JavaThread *thread) { 20.8 20.9 -bool frame::safe_for_sender(JavaThread *thread) { 20.10 - address sp = (address)_sp; 20.11 - if (sp != NULL && 20.12 - (sp <= thread->stack_base() && sp >= thread->stack_base() - thread->stack_size())) { 20.13 - // Unfortunately we can only check frame complete for runtime stubs and nmethod 20.14 - // other generic buffer blobs are more problematic so we just assume they are 20.15 - // ok. adapter blobs never have a frame complete and are never ok. 20.16 - if (_cb != NULL && !_cb->is_frame_complete_at(_pc)) { 20.17 - if (_cb->is_nmethod() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) { 20.18 - return false; 20.19 - } 20.20 + address _SP = (address) sp(); 20.21 + address _FP = (address) fp(); 20.22 + address _UNEXTENDED_SP = (address) unextended_sp(); 20.23 + // sp must be within the stack 20.24 + bool sp_safe = (_SP <= thread->stack_base()) && 20.25 + (_SP >= thread->stack_base() - thread->stack_size()); 20.26 + 20.27 + if (!sp_safe) { 20.28 + return false; 20.29 + } 20.30 + 20.31 + // unextended sp must be within the stack and above or equal sp 20.32 + bool unextended_sp_safe = (_UNEXTENDED_SP <= thread->stack_base()) && 20.33 + (_UNEXTENDED_SP >= _SP); 20.34 + 20.35 + if (!unextended_sp_safe) return false; 20.36 + 20.37 + // an fp must be within the stack and above (but not equal) sp 20.38 + bool fp_safe = (_FP <= thread->stack_base()) && 20.39 + (_FP > _SP); 20.40 + 20.41 + // We know sp/unextended_sp are safe only fp is questionable here 20.42 + 20.43 + // If the current frame is known to the code cache then we can attempt to 20.44 + // to construct the sender and do some validation of it. This goes a long way 20.45 + // toward eliminating issues when we get in frame construction code 20.46 + 20.47 + if (_cb != NULL ) { 20.48 + 20.49 + // First check if frame is complete and tester is reliable 20.50 + // Unfortunately we can only check frame complete for runtime stubs and nmethod 20.51 + // other generic buffer blobs are more problematic so we just assume they are 20.52 + // ok. adapter blobs never have a frame complete and are never ok. 20.53 + 20.54 + if (!_cb->is_frame_complete_at(_pc)) { 20.55 + if (_cb->is_nmethod() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) { 20.56 + return false; 20.57 } 20.58 - return true; 20.59 + } 20.60 + 20.61 + // Entry frame checks 20.62 + if (is_entry_frame()) { 20.63 + // an entry frame must have a valid fp. 20.64 + 20.65 + if (!fp_safe) { 20.66 + return false; 20.67 + } 20.68 + 20.69 + // Validate the JavaCallWrapper an entry frame must have 20.70 + 20.71 + address jcw = (address)entry_frame_call_wrapper(); 20.72 + 20.73 + bool jcw_safe = (jcw <= thread->stack_base()) && ( jcw > _FP); 20.74 + 20.75 + return jcw_safe; 20.76 + 20.77 + } 20.78 + 20.79 + intptr_t* younger_sp = sp(); 20.80 + intptr_t* _SENDER_SP = sender_sp(); // sender is actually just _FP 20.81 + bool adjusted_stack = is_interpreted_frame(); 20.82 + 20.83 + address sender_pc = (address)younger_sp[I7->sp_offset_in_saved_window()] + pc_return_offset; 20.84 + 20.85 + 20.86 + // We must always be able to find a recognizable pc 20.87 + CodeBlob* sender_blob = CodeCache::find_blob_unsafe(sender_pc); 20.88 + if (sender_pc == NULL || sender_blob == NULL) { 20.89 + return false; 20.90 + } 20.91 + 20.92 + // It should be safe to construct the sender though it might not be valid 20.93 + 20.94 + frame sender(_SENDER_SP, younger_sp, adjusted_stack); 20.95 + 20.96 + // Do we have a valid fp? 20.97 + address sender_fp = (address) sender.fp(); 20.98 + 20.99 + // an fp must be within the stack and above (but not equal) current frame's _FP 20.100 + 20.101 + bool sender_fp_safe = (sender_fp <= thread->stack_base()) && 20.102 + (sender_fp > _FP); 20.103 + 20.104 + if (!sender_fp_safe) { 20.105 + return false; 20.106 + } 20.107 + 20.108 + 20.109 + // If the potential sender is the interpreter then we can do some more checking 20.110 + if (Interpreter::contains(sender_pc)) { 20.111 + return sender.is_interpreted_frame_valid(thread); 20.112 + } 20.113 + 20.114 + // Could just be some random pointer within the codeBlob 20.115 + if (!sender.cb()->instructions_contains(sender_pc)) return false; 20.116 + 20.117 + // We should never be able to see an adapter if the current frame is something from code cache 20.118 + 20.119 + if ( sender_blob->is_adapter_blob()) { 20.120 + return false; 20.121 + } 20.122 + 20.123 + if( sender.is_entry_frame()) { 20.124 + // Validate the JavaCallWrapper an entry frame must have 20.125 + 20.126 + address jcw = (address)sender.entry_frame_call_wrapper(); 20.127 + 20.128 + bool jcw_safe = (jcw <= thread->stack_base()) && ( jcw > sender_fp); 20.129 + 20.130 + return jcw_safe; 20.131 + } 20.132 + 20.133 + // If the frame size is 0 something is bad because every nmethod has a non-zero frame size 20.134 + // because you must allocate window space 20.135 + 20.136 + if (sender_blob->frame_size() == 0) { 20.137 + assert(!sender_blob->is_nmethod(), "should count return address at least"); 20.138 + return false; 20.139 + } 20.140 + 20.141 + // The sender should positively be an nmethod or call_stub. On sparc we might in fact see something else. 20.142 + // The cause of this is because at a save instruction the O7 we get is a leftover from an earlier 20.143 + // window use. So if a runtime stub creates two frames (common in fastdebug/jvmg) then we see the 20.144 + // stale pc. So if the sender blob is not something we'd expect we have little choice but to declare 20.145 + // the stack unwalkable. pd_get_top_frame_for_signal_handler tries to recover from this by unwinding 20.146 + // that initial frame and retrying. 20.147 + 20.148 + if (!sender_blob->is_nmethod()) { 20.149 + return false; 20.150 + } 20.151 + 20.152 + // Could put some more validation for the potential non-interpreted sender 20.153 + // frame we'd create by calling sender if I could think of any. Wait for next crash in forte... 20.154 + 20.155 + // One idea is seeing if the sender_pc we have is one that we'd expect to call to current cb 20.156 + 20.157 + // We've validated the potential sender that would be created 20.158 + 20.159 + return true; 20.160 + 20.161 } 20.162 - return false; 20.163 + 20.164 + // Must be native-compiled frame. Since sender will try and use fp to find 20.165 + // linkages it must be safe 20.166 + 20.167 + if (!fp_safe) return false; 20.168 + 20.169 + // could try and do some more potential verification of native frame if we could think of some... 20.170 + 20.171 + return true; 20.172 } 20.173 20.174 // constructors 20.175 @@ -450,7 +586,7 @@ 20.176 } 20.177 20.178 20.179 -bool frame::is_interpreted_frame_valid() const { 20.180 +bool frame::is_interpreted_frame_valid(JavaThread* thread) const { 20.181 #ifdef CC_INTERP 20.182 // Is there anything to do? 20.183 #else 20.184 @@ -462,6 +598,7 @@ 20.185 if (sp() == 0 || (intptr_t(sp()) & (2*wordSize-1)) != 0) { 20.186 return false; 20.187 } 20.188 + 20.189 const intptr_t interpreter_frame_initial_sp_offset = interpreter_frame_vm_local_words; 20.190 if (fp() + interpreter_frame_initial_sp_offset < sp()) { 20.191 return false; 20.192 @@ -471,9 +608,43 @@ 20.193 if (fp() <= sp()) { // this attempts to deal with unsigned comparison above 20.194 return false; 20.195 } 20.196 - if (fp() - sp() > 4096) { // stack frames shouldn't be large. 20.197 + // do some validation of frame elements 20.198 + 20.199 + // first the method 20.200 + 20.201 + methodOop m = *interpreter_frame_method_addr(); 20.202 + 20.203 + // validate the method we'd find in this potential sender 20.204 + if (!Universe::heap()->is_valid_method(m)) return false; 20.205 + 20.206 + // stack frames shouldn't be much larger than max_stack elements 20.207 + 20.208 + if (fp() - sp() > 1024 + m->max_stack()*Interpreter::stackElementSize()) { 20.209 return false; 20.210 } 20.211 + 20.212 + // validate bci/bcx 20.213 + 20.214 + intptr_t bcx = interpreter_frame_bcx(); 20.215 + if (m->validate_bci_from_bcx(bcx) < 0) { 20.216 + return false; 20.217 + } 20.218 + 20.219 + // validate constantPoolCacheOop 20.220 + 20.221 + constantPoolCacheOop cp = *interpreter_frame_cache_addr(); 20.222 + 20.223 + if (cp == NULL || 20.224 + !Space::is_aligned(cp) || 20.225 + !Universe::heap()->is_permanent((void*)cp)) return false; 20.226 + 20.227 + // validate locals 20.228 + 20.229 + address locals = (address) *interpreter_frame_locals_addr(); 20.230 + 20.231 + if (locals > thread->stack_base() || locals < (address) fp()) return false; 20.232 + 20.233 + // We'd have to be pretty unlucky to be mislead at this point 20.234 #endif /* CC_INTERP */ 20.235 return true; 20.236 }
21.1 --- a/src/cpu/x86/vm/disassembler_x86.cpp Thu Apr 10 15:49:16 2008 -0400 21.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 21.3 @@ -1,201 +0,0 @@ 21.4 -/* 21.5 - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. 21.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 21.7 - * 21.8 - * This code is free software; you can redistribute it and/or modify it 21.9 - * under the terms of the GNU General Public License version 2 only, as 21.10 - * published by the Free Software Foundation. 21.11 - * 21.12 - * This code is distributed in the hope that it will be useful, but WITHOUT 21.13 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 21.14 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 21.15 - * version 2 for more details (a copy is included in the LICENSE file that 21.16 - * accompanied this code). 21.17 - * 21.18 - * You should have received a copy of the GNU General Public License version 21.19 - * 2 along with this work; if not, write to the Free Software Foundation, 21.20 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21.21 - * 21.22 - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 21.23 - * CA 95054 USA or visit www.sun.com if you need additional information or 21.24 - * have any questions. 21.25 - * 21.26 - */ 21.27 - 21.28 -# include "incls/_precompiled.incl" 21.29 -# include "incls/_disassembler_x86.cpp.incl" 21.30 - 21.31 -#ifndef PRODUCT 21.32 - 21.33 -void* Disassembler::_library = NULL; 21.34 -Disassembler::decode_func Disassembler::_decode_instruction = NULL; 21.35 - 21.36 -bool Disassembler::load_library() { 21.37 - if (_library == NULL) { 21.38 - char buf[1024]; 21.39 - char ebuf[1024]; 21.40 - sprintf(buf, "disassembler%s", os::dll_file_extension()); 21.41 - _library = hpi::dll_load(buf, ebuf, sizeof ebuf); 21.42 - if (_library != NULL) { 21.43 - tty->print_cr("Loaded disassembler"); 21.44 - _decode_instruction = CAST_TO_FN_PTR(Disassembler::decode_func, hpi::dll_lookup(_library, "decode_instruction")); 21.45 - } 21.46 - } 21.47 - return (_library != NULL) && (_decode_instruction != NULL); 21.48 -} 21.49 - 21.50 -class x86_env : public DisassemblerEnv { 21.51 - private: 21.52 - nmethod* code; 21.53 - outputStream* output; 21.54 - public: 21.55 - x86_env(nmethod* rcode, outputStream* routput) { 21.56 - code = rcode; 21.57 - output = routput; 21.58 - } 21.59 - void print_label(intptr_t value); 21.60 - void print_raw(char* str) { output->print_raw(str); } 21.61 - void print(char* format, ...); 21.62 - char* string_for_offset(intptr_t value); 21.63 - char* string_for_constant(unsigned char* pc, intptr_t value, int is_decimal); 21.64 -}; 21.65 - 21.66 - 21.67 -void x86_env::print_label(intptr_t value) { 21.68 - if (!Universe::is_fully_initialized()) { 21.69 - output->print(INTPTR_FORMAT, value); 21.70 - return; 21.71 - } 21.72 - address adr = (address) value; 21.73 - if (StubRoutines::contains(adr)) { 21.74 - StubCodeDesc* desc = StubCodeDesc::desc_for(adr); 21.75 - const char * desc_name = "unknown stub"; 21.76 - if (desc != NULL) { 21.77 - desc_name = desc->name(); 21.78 - } 21.79 - output->print("Stub::%s", desc_name); 21.80 - if (WizardMode) output->print(" " INTPTR_FORMAT, value); 21.81 - } else { 21.82 - output->print(INTPTR_FORMAT, value); 21.83 - } 21.84 -} 21.85 - 21.86 -void x86_env::print(char* format, ...) { 21.87 - va_list ap; 21.88 - va_start(ap, format); 21.89 - output->vprint(format, ap); 21.90 - va_end(ap); 21.91 -} 21.92 - 21.93 -char* x86_env::string_for_offset(intptr_t value) { 21.94 - stringStream st; 21.95 - if (!Universe::is_fully_initialized()) { 21.96 - st.print(INTX_FORMAT, value); 21.97 - return st.as_string(); 21.98 - } 21.99 - BarrierSet* bs = Universe::heap()->barrier_set(); 21.100 - BarrierSet::Name bsn = bs->kind(); 21.101 - if (bs->kind() == BarrierSet::CardTableModRef && 21.102 - (jbyte*) value == ((CardTableModRefBS*)(bs))->byte_map_base) { 21.103 - st.print("word_map_base"); 21.104 - } else { 21.105 - st.print(INTX_FORMAT, value); 21.106 - } 21.107 - return st.as_string(); 21.108 -} 21.109 - 21.110 -char* x86_env::string_for_constant(unsigned char* pc, intptr_t value, int is_decimal) { 21.111 - stringStream st; 21.112 - oop obj = NULL; 21.113 - if (code && ((obj = code->embeddedOop_at(pc)) != NULL)) { 21.114 - obj->print_value_on(&st); 21.115 - } else { 21.116 - if (is_decimal == 1) { 21.117 - st.print(INTX_FORMAT, value); 21.118 - } else { 21.119 - st.print(INTPTR_FORMAT, value); 21.120 - } 21.121 - } 21.122 - return st.as_string(); 21.123 -} 21.124 - 21.125 - 21.126 - 21.127 -address Disassembler::decode_instruction(address start, DisassemblerEnv* env) { 21.128 - return ((decode_func) _decode_instruction)(start, env); 21.129 -} 21.130 - 21.131 - 21.132 -void Disassembler::decode(CodeBlob* cb, outputStream* st) { 21.133 - st = st ? st : tty; 21.134 - st->print_cr("Decoding CodeBlob " INTPTR_FORMAT, cb); 21.135 - decode(cb->instructions_begin(), cb->instructions_end(), st); 21.136 -} 21.137 - 21.138 - 21.139 -void Disassembler::decode(u_char* begin, u_char* end, outputStream* st) { 21.140 - st = st ? st : tty; 21.141 - 21.142 - const int show_bytes = false; // for disassembler debugging 21.143 - 21.144 - if (!load_library()) { 21.145 - st->print_cr("Could not load disassembler"); 21.146 - return; 21.147 - } 21.148 - 21.149 - x86_env env(NULL, st); 21.150 - unsigned char* p = (unsigned char*) begin; 21.151 - CodeBlob* cb = CodeCache::find_blob_unsafe(begin); 21.152 - while (p < (unsigned char*) end) { 21.153 - if (cb != NULL) { 21.154 - cb->print_block_comment(st, (intptr_t)(p - cb->instructions_begin())); 21.155 - } 21.156 - 21.157 - unsigned char* p0 = p; 21.158 - st->print(" " INTPTR_FORMAT ": ", p); 21.159 - p = decode_instruction(p, &env); 21.160 - if (show_bytes) { 21.161 - st->print("\t\t\t"); 21.162 - while (p0 < p) st->print("%x ", *p0++); 21.163 - } 21.164 - st->cr(); 21.165 - } 21.166 -} 21.167 - 21.168 - 21.169 -void Disassembler::decode(nmethod* nm, outputStream* st) { 21.170 - st = st ? st : tty; 21.171 - 21.172 - st->print_cr("Decoding compiled method " INTPTR_FORMAT ":", nm); 21.173 - st->print("Code:"); 21.174 - st->cr(); 21.175 - 21.176 - if (!load_library()) { 21.177 - st->print_cr("Could not load disassembler"); 21.178 - return; 21.179 - } 21.180 - x86_env env(nm, st); 21.181 - unsigned char* p = nm->instructions_begin(); 21.182 - unsigned char* end = nm->instructions_end(); 21.183 - while (p < end) { 21.184 - if (p == nm->entry_point()) st->print_cr("[Entry Point]"); 21.185 - if (p == nm->verified_entry_point()) st->print_cr("[Verified Entry Point]"); 21.186 - if (p == nm->exception_begin()) st->print_cr("[Exception Handler]"); 21.187 - if (p == nm->stub_begin()) st->print_cr("[Stub Code]"); 21.188 - if (p == nm->consts_begin()) st->print_cr("[Constants]"); 21.189 - nm->print_block_comment(st, (intptr_t)(p - nm->instructions_begin())); 21.190 - unsigned char* p0 = p; 21.191 - st->print(" " INTPTR_FORMAT ": ", p); 21.192 - p = decode_instruction(p, &env); 21.193 - nm->print_code_comment_on(st, 40, p0, p); 21.194 - st->cr(); 21.195 - // Output pc bucket ticks if we have any 21.196 - address bucket_pc = FlatProfiler::bucket_start_for(p); 21.197 - if (bucket_pc != NULL && bucket_pc > p0 && bucket_pc <= p) { 21.198 - int bucket_count = FlatProfiler::bucket_count_for(bucket_pc); 21.199 - tty->print_cr("[%d]", bucket_count); 21.200 - } 21.201 - } 21.202 -} 21.203 - 21.204 -#endif // PRODUCT
22.1 --- a/src/cpu/x86/vm/disassembler_x86.hpp Thu Apr 10 15:49:16 2008 -0400 22.2 +++ b/src/cpu/x86/vm/disassembler_x86.hpp Fri Apr 11 09:56:35 2008 -0400 22.3 @@ -1,5 +1,5 @@ 22.4 /* 22.5 - * Copyright 1997-1999 Sun Microsystems, Inc. All Rights Reserved. 22.6 + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. 22.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 22.8 * 22.9 * This code is free software; you can redistribute it and/or modify it 22.10 @@ -22,24 +22,10 @@ 22.11 * 22.12 */ 22.13 22.14 -// The disassembler prints out intel 386 code annotated 22.15 -// with Java specific information. 22.16 + static int pd_instruction_alignment() { 22.17 + return 1; 22.18 + } 22.19 22.20 -class Disassembler { 22.21 -#ifndef PRODUCT 22.22 - private: 22.23 - typedef address (*decode_func)(address start, DisassemblerEnv* env); 22.24 - // points the library. 22.25 - static void* _library; 22.26 - // points to the decode function. 22.27 - static decode_func _decode_instruction; 22.28 - // tries to load library and return whether it succedded. 22.29 - static bool load_library(); 22.30 - // decodes one instruction and return the start of the next instruction. 22.31 - static address decode_instruction(address start, DisassemblerEnv* env); 22.32 -#endif 22.33 - public: 22.34 - static void decode(CodeBlob *cb, outputStream* st = NULL) PRODUCT_RETURN; 22.35 - static void decode(nmethod* nm, outputStream* st = NULL) PRODUCT_RETURN; 22.36 - static void decode(u_char* begin, u_char* end, outputStream* st = NULL) PRODUCT_RETURN; 22.37 -}; 22.38 + static const char* pd_cpu_opts() { 22.39 + return ""; 22.40 + }
23.1 --- a/src/cpu/x86/vm/frame_x86.cpp Thu Apr 10 15:49:16 2008 -0400 23.2 +++ b/src/cpu/x86/vm/frame_x86.cpp Fri Apr 11 09:56:35 2008 -0400 23.3 @@ -37,39 +37,181 @@ 23.4 address sp = (address)_sp; 23.5 address fp = (address)_fp; 23.6 address unextended_sp = (address)_unextended_sp; 23.7 - bool sp_safe = (sp != NULL && 23.8 - (sp <= thread->stack_base()) && 23.9 - (sp >= thread->stack_base() - thread->stack_size())); 23.10 - bool unextended_sp_safe = (unextended_sp != NULL && 23.11 - (unextended_sp <= thread->stack_base()) && 23.12 - (unextended_sp >= thread->stack_base() - thread->stack_size())); 23.13 - bool fp_safe = (fp != NULL && 23.14 - (fp <= thread->stack_base()) && 23.15 - (fp >= thread->stack_base() - thread->stack_size())); 23.16 - if (sp_safe && unextended_sp_safe && fp_safe) { 23.17 + // sp must be within the stack 23.18 + bool sp_safe = (sp <= thread->stack_base()) && 23.19 + (sp >= thread->stack_base() - thread->stack_size()); 23.20 + 23.21 + if (!sp_safe) { 23.22 + return false; 23.23 + } 23.24 + 23.25 + // unextended sp must be within the stack and above or equal sp 23.26 + bool unextended_sp_safe = (unextended_sp <= thread->stack_base()) && 23.27 + (unextended_sp >= sp); 23.28 + 23.29 + if (!unextended_sp_safe) { 23.30 + return false; 23.31 + } 23.32 + 23.33 + // an fp must be within the stack and above (but not equal) sp 23.34 + bool fp_safe = (fp <= thread->stack_base()) && (fp > sp); 23.35 + 23.36 + // We know sp/unextended_sp are safe only fp is questionable here 23.37 + 23.38 + // If the current frame is known to the code cache then we can attempt to 23.39 + // to construct the sender and do some validation of it. This goes a long way 23.40 + // toward eliminating issues when we get in frame construction code 23.41 + 23.42 + if (_cb != NULL ) { 23.43 + 23.44 + // First check if frame is complete and tester is reliable 23.45 // Unfortunately we can only check frame complete for runtime stubs and nmethod 23.46 // other generic buffer blobs are more problematic so we just assume they are 23.47 // ok. adapter blobs never have a frame complete and are never ok. 23.48 - if (_cb != NULL && !_cb->is_frame_complete_at(_pc)) { 23.49 + 23.50 + if (!_cb->is_frame_complete_at(_pc)) { 23.51 if (_cb->is_nmethod() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) { 23.52 return false; 23.53 } 23.54 } 23.55 + // Entry frame checks 23.56 + if (is_entry_frame()) { 23.57 + // an entry frame must have a valid fp. 23.58 + 23.59 + if (!fp_safe) return false; 23.60 + 23.61 + // Validate the JavaCallWrapper an entry frame must have 23.62 + 23.63 + address jcw = (address)entry_frame_call_wrapper(); 23.64 + 23.65 + bool jcw_safe = (jcw <= thread->stack_base()) && ( jcw > fp); 23.66 + 23.67 + return jcw_safe; 23.68 + 23.69 + } 23.70 + 23.71 + intptr_t* sender_sp = NULL; 23.72 + address sender_pc = NULL; 23.73 + 23.74 + if (is_interpreted_frame()) { 23.75 + // fp must be safe 23.76 + if (!fp_safe) { 23.77 + return false; 23.78 + } 23.79 + 23.80 + sender_pc = (address) this->fp()[return_addr_offset]; 23.81 + sender_sp = (intptr_t*) addr_at(sender_sp_offset); 23.82 + 23.83 + } else { 23.84 + // must be some sort of compiled/runtime frame 23.85 + // fp does not have to be safe (although it could be check for c1?) 23.86 + 23.87 + sender_sp = _unextended_sp + _cb->frame_size(); 23.88 + // On Intel the return_address is always the word on the stack 23.89 + sender_pc = (address) *(sender_sp-1); 23.90 + } 23.91 + 23.92 + // We must always be able to find a recognizable pc 23.93 + CodeBlob* sender_blob = CodeCache::find_blob_unsafe(sender_pc); 23.94 + if (sender_pc == NULL || sender_blob == NULL) { 23.95 + return false; 23.96 + } 23.97 + 23.98 + 23.99 + // If the potential sender is the interpreter then we can do some more checking 23.100 + if (Interpreter::contains(sender_pc)) { 23.101 + 23.102 + // ebp is always saved in a recognizable place in any code we generate. However 23.103 + // only if the sender is interpreted/call_stub (c1 too?) are we certain that the saved ebp 23.104 + // is really a frame pointer. 23.105 + 23.106 + intptr_t *saved_fp = (intptr_t*)*(sender_sp - frame::sender_sp_offset); 23.107 + bool saved_fp_safe = ((address)saved_fp <= thread->stack_base()) && (saved_fp > sender_sp); 23.108 + 23.109 + if (!saved_fp_safe) { 23.110 + return false; 23.111 + } 23.112 + 23.113 + // construct the potential sender 23.114 + 23.115 + frame sender(sender_sp, saved_fp, sender_pc); 23.116 + 23.117 + return sender.is_interpreted_frame_valid(thread); 23.118 + 23.119 + } 23.120 + 23.121 + // Could just be some random pointer within the codeBlob 23.122 + 23.123 + if (!sender_blob->instructions_contains(sender_pc)) return false; 23.124 + 23.125 + // We should never be able to see an adapter if the current frame is something from code cache 23.126 + 23.127 + if ( sender_blob->is_adapter_blob()) { 23.128 + return false; 23.129 + } 23.130 + 23.131 + // Could be the call_stub 23.132 + 23.133 + if (StubRoutines::returns_to_call_stub(sender_pc)) { 23.134 + intptr_t *saved_fp = (intptr_t*)*(sender_sp - frame::sender_sp_offset); 23.135 + bool saved_fp_safe = ((address)saved_fp <= thread->stack_base()) && (saved_fp > sender_sp); 23.136 + 23.137 + if (!saved_fp_safe) { 23.138 + return false; 23.139 + } 23.140 + 23.141 + // construct the potential sender 23.142 + 23.143 + frame sender(sender_sp, saved_fp, sender_pc); 23.144 + 23.145 + // Validate the JavaCallWrapper an entry frame must have 23.146 + address jcw = (address)sender.entry_frame_call_wrapper(); 23.147 + 23.148 + bool jcw_safe = (jcw <= thread->stack_base()) && ( jcw > (address)sender.fp()); 23.149 + 23.150 + return jcw_safe; 23.151 + } 23.152 + 23.153 + // If the frame size is 0 something is bad because every nmethod has a non-zero frame size 23.154 + // because the return address counts against the callee's frame. 23.155 + 23.156 + if (sender_blob->frame_size() == 0) { 23.157 + assert(!sender_blob->is_nmethod(), "should count return address at least"); 23.158 + return false; 23.159 + } 23.160 + 23.161 + // We should never be able to see anything here except an nmethod. If something in the 23.162 + // code cache (current frame) is called by an entity within the code cache that entity 23.163 + // should not be anything but the call stub (already covered), the interpreter (already covered) 23.164 + // or an nmethod. 23.165 + 23.166 + assert(sender_blob->is_nmethod(), "Impossible call chain"); 23.167 + 23.168 + // Could put some more validation for the potential non-interpreted sender 23.169 + // frame we'd create by calling sender if I could think of any. Wait for next crash in forte... 23.170 + 23.171 + // One idea is seeing if the sender_pc we have is one that we'd expect to call to current cb 23.172 + 23.173 + // We've validated the potential sender that would be created 23.174 return true; 23.175 } 23.176 - // Note: fp == NULL is not really a prerequisite for this to be safe to 23.177 - // walk for c2. However we've modified the code such that if we get 23.178 - // a failure with fp != NULL that we then try with FP == NULL. 23.179 - // This is basically to mimic what a last_frame would look like if 23.180 - // c2 had generated it. 23.181 - if (sp_safe && unextended_sp_safe && fp == NULL) { 23.182 - // frame must be complete if fp == NULL as fp == NULL is only sensible 23.183 - // if we are looking at a nmethod and frame complete assures us of that. 23.184 - if (_cb != NULL && _cb->is_frame_complete_at(_pc) && _cb->is_compiled_by_c2()) { 23.185 - return true; 23.186 - } 23.187 + 23.188 + // Must be native-compiled frame. Since sender will try and use fp to find 23.189 + // linkages it must be safe 23.190 + 23.191 + if (!fp_safe) { 23.192 + return false; 23.193 } 23.194 - return false; 23.195 + 23.196 + // Will the pc we fetch be non-zero (which we'll find at the oldest frame) 23.197 + 23.198 + if ( (address) this->fp()[return_addr_offset] == NULL) return false; 23.199 + 23.200 + 23.201 + // could try and do some more potential verification of native frame if we could think of some... 23.202 + 23.203 + return true; 23.204 + 23.205 } 23.206 23.207 23.208 @@ -292,7 +434,7 @@ 23.209 // nothing done here now 23.210 } 23.211 23.212 -bool frame::is_interpreted_frame_valid() const { 23.213 +bool frame::is_interpreted_frame_valid(JavaThread* thread) const { 23.214 // QQQ 23.215 #ifdef CC_INTERP 23.216 #else 23.217 @@ -312,9 +454,45 @@ 23.218 if (fp() <= sp()) { // this attempts to deal with unsigned comparison above 23.219 return false; 23.220 } 23.221 - if (fp() - sp() > 4096) { // stack frames shouldn't be large. 23.222 + 23.223 + // do some validation of frame elements 23.224 + 23.225 + // first the method 23.226 + 23.227 + methodOop m = *interpreter_frame_method_addr(); 23.228 + 23.229 + // validate the method we'd find in this potential sender 23.230 + if (!Universe::heap()->is_valid_method(m)) return false; 23.231 + 23.232 + // stack frames shouldn't be much larger than max_stack elements 23.233 + 23.234 + if (fp() - sp() > 1024 + m->max_stack()*Interpreter::stackElementSize()) { 23.235 return false; 23.236 } 23.237 + 23.238 + // validate bci/bcx 23.239 + 23.240 + intptr_t bcx = interpreter_frame_bcx(); 23.241 + if (m->validate_bci_from_bcx(bcx) < 0) { 23.242 + return false; 23.243 + } 23.244 + 23.245 + // validate constantPoolCacheOop 23.246 + 23.247 + constantPoolCacheOop cp = *interpreter_frame_cache_addr(); 23.248 + 23.249 + if (cp == NULL || 23.250 + !Space::is_aligned(cp) || 23.251 + !Universe::heap()->is_permanent((void*)cp)) return false; 23.252 + 23.253 + // validate locals 23.254 + 23.255 + address locals = (address) *interpreter_frame_locals_addr(); 23.256 + 23.257 + if (locals > thread->stack_base() || locals < (address) fp()) return false; 23.258 + 23.259 + // We'd have to be pretty unlucky to be mislead at this point 23.260 + 23.261 #endif // CC_INTERP 23.262 return true; 23.263 }
24.1 --- a/src/cpu/x86/vm/frame_x86.inline.hpp Thu Apr 10 15:49:16 2008 -0400 24.2 +++ b/src/cpu/x86/vm/frame_x86.inline.hpp Fri Apr 11 09:56:35 2008 -0400 24.3 @@ -72,15 +72,20 @@ 24.4 _unextended_sp = sp; 24.5 _fp = fp; 24.6 _pc = (address)(sp[-1]); 24.7 - assert(_pc != NULL, "no pc?"); 24.8 + 24.9 + // Here's a sticky one. This constructor can be called via AsyncGetCallTrace 24.10 + // when last_Java_sp is non-null but the pc fetched is junk. If we are truly 24.11 + // unlucky the junk value could be to a zombied method and we'll die on the 24.12 + // find_blob call. This is also why we can have no asserts on the validity 24.13 + // of the pc we find here. AsyncGetCallTrace -> pd_get_top_frame_for_signal_handler 24.14 + // -> pd_last_frame should use a specialized version of pd_last_frame which could 24.15 + // call a specilaized frame constructor instead of this one. 24.16 + // Then we could use the assert below. However this assert is of somewhat dubious 24.17 + // value. 24.18 + // assert(_pc != NULL, "no pc?"); 24.19 + 24.20 _cb = CodeCache::find_blob(_pc); 24.21 - // In case of native stubs, the pc retreived here might be 24.22 - // wrong. (the _last_native_pc will have the right value) 24.23 - // So do not put add any asserts on the _pc here. 24.24 24.25 - // QQQ The above comment is wrong and has been wrong for years. This constructor 24.26 - // should (and MUST) not be called in that situation. In the native situation 24.27 - // the pc should be supplied to the constructor. 24.28 _deopt_state = not_deoptimized; 24.29 if (_cb != NULL && _cb->is_nmethod() && ((nmethod*)_cb)->is_deopt_pc(_pc)) { 24.30 _pc = (((nmethod*)_cb)->get_original_pc(this));
25.1 --- a/src/cpu/x86/vm/templateTable_x86_32.cpp Thu Apr 10 15:49:16 2008 -0400 25.2 +++ b/src/cpu/x86/vm/templateTable_x86_32.cpp Fri Apr 11 09:56:35 2008 -0400 25.3 @@ -1632,7 +1632,7 @@ 25.4 // We need to prepare to execute the OSR method. First we must 25.5 // migrate the locals and monitors off of the stack. 25.6 25.7 - __ movl(rsi, rax); // save the nmethod 25.8 + __ movl(rbx, rax); // save the nmethod 25.9 25.10 const Register thread = rcx; 25.11 __ get_thread(thread); 25.12 @@ -1688,7 +1688,7 @@ 25.13 __ pushl(rdi); 25.14 25.15 // and begin the OSR nmethod 25.16 - __ jmp(Address(rsi, nmethod::osr_entry_point_offset())); 25.17 + __ jmp(Address(rbx, nmethod::osr_entry_point_offset())); 25.18 } 25.19 } 25.20 }
26.1 --- a/src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.cpp Thu Apr 10 15:49:16 2008 -0400 26.2 +++ b/src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.cpp Fri Apr 11 09:56:35 2008 -0400 26.3 @@ -50,17 +50,6 @@ 26.4 // even if isInJava == true. It should be more reliable than 26.5 // ucontext info. 26.6 if (jt->has_last_Java_frame() && jt->frame_anchor()->walkable()) { 26.7 -#if 0 26.8 - // This sanity check may not be needed with the new frame 26.9 - // walking code. Remove it for now. 26.10 - if (!jt->frame_anchor()->post_Java_state_is_pc() 26.11 - && frame::next_younger_sp_or_null(last_Java_sp(), 26.12 - jt->frame_anchor()->post_Java_sp()) == NULL) { 26.13 - // the anchor contains an SP, but the frame is not walkable 26.14 - // because post_Java_sp isn't valid relative to last_Java_sp 26.15 - return false; 26.16 - } 26.17 -#endif 26.18 *fr_addr = jt->pd_last_frame(); 26.19 return true; 26.20 } 26.21 @@ -77,23 +66,59 @@ 26.22 return false; 26.23 } 26.24 26.25 + frame ret_frame(ret_sp, frame::unpatchable, addr.pc()); 26.26 + 26.27 // we were running Java code when SIGPROF came in 26.28 if (isInJava) { 26.29 + 26.30 + 26.31 + // If the frame we got is safe then it is most certainly valid 26.32 + if (ret_frame.safe_for_sender(jt)) { 26.33 + *fr_addr = ret_frame; 26.34 + return true; 26.35 + } 26.36 + 26.37 + // If it isn't safe then we can try several things to try and get 26.38 + // a good starting point. 26.39 + // 26.40 + // On sparc the frames are almost certainly walkable in the sense 26.41 + // of sp/fp linkages. However because of recycling of windows if 26.42 + // a piece of code does multiple save's where the initial save creates 26.43 + // a real frame with a return pc and the succeeding save's are used to 26.44 + // simply get free registers and have no real pc then the pc linkage on these 26.45 + // "inner" temporary frames will be bogus. 26.46 + // Since there is in general only a nesting level like 26.47 + // this one deep in general we'll try and unwind such an "inner" frame 26.48 + // here ourselves and see if it makes sense 26.49 + 26.50 + frame unwind_frame(ret_frame.fp(), frame::unpatchable, addr.pc()); 26.51 + 26.52 + if (unwind_frame.safe_for_sender(jt)) { 26.53 + *fr_addr = unwind_frame; 26.54 + return true; 26.55 + } 26.56 + 26.57 + // Well that didn't work. Most likely we're toast on this tick 26.58 + // The previous code would try this. I think it is dubious in light 26.59 + // of changes to safe_for_sender and the unwind trick above but 26.60 + // if it gets us a safe frame who wants to argue. 26.61 + 26.62 // If we have a last_Java_sp, then the SIGPROF signal caught us 26.63 // right when we were transitioning from _thread_in_Java to a new 26.64 // JavaThreadState. We use last_Java_sp instead of the sp from 26.65 // the ucontext since it should be more reliable. 26.66 + 26.67 if (jt->has_last_Java_frame()) { 26.68 ret_sp = jt->last_Java_sp(); 26.69 + frame ret_frame2(ret_sp, frame::unpatchable, addr.pc()); 26.70 + if (ret_frame2.safe_for_sender(jt)) { 26.71 + *fr_addr = ret_frame2; 26.72 + return true; 26.73 + } 26.74 } 26.75 - // Implied else: we don't have a last_Java_sp so we use what we 26.76 - // got from the ucontext. 26.77 26.78 - frame ret_frame(ret_sp, frame::unpatchable, addr.pc()); 26.79 - if (!ret_frame.safe_for_sender(jt)) { 26.80 - // nothing else to try if the frame isn't good 26.81 - return false; 26.82 - } 26.83 + // This is the best we can do. We will only be able to decode the top frame 26.84 + 26.85 *fr_addr = ret_frame; 26.86 return true; 26.87 } 26.88 @@ -105,17 +130,13 @@ 26.89 if (jt->has_last_Java_frame()) { 26.90 assert(!jt->frame_anchor()->walkable(), "case covered above"); 26.91 26.92 - if (jt->thread_state() == _thread_in_native) { 26.93 - frame ret_frame(jt->last_Java_sp(), frame::unpatchable, addr.pc()); 26.94 - if (!ret_frame.safe_for_sender(jt)) { 26.95 - // nothing else to try if the frame isn't good 26.96 - return false; 26.97 - } 26.98 - *fr_addr = ret_frame; 26.99 - return true; 26.100 - } 26.101 + frame ret_frame(jt->last_Java_sp(), frame::unpatchable, addr.pc()); 26.102 + *fr_addr = ret_frame; 26.103 + return true; 26.104 } 26.105 26.106 - // nothing else to try 26.107 - return false; 26.108 + // nothing else to try but what we found initially 26.109 + 26.110 + *fr_addr = ret_frame; 26.111 + return true; 26.112 }
27.1 --- a/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Thu Apr 10 15:49:16 2008 -0400 27.2 +++ b/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Fri Apr 11 09:56:35 2008 -0400 27.3 @@ -212,7 +212,8 @@ 27.4 CAST_FROM_FN_PTR(address, os::current_frame)); 27.5 if (os::is_first_C_frame(&myframe)) { 27.6 // stack is not walkable 27.7 - return frame(NULL, NULL, NULL); 27.8 + frame ret; // This will be a null useless frame 27.9 + return ret; 27.10 } else { 27.11 return os::get_sender_for_C_frame(&myframe); 27.12 }
28.1 --- a/src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp Thu Apr 10 15:49:16 2008 -0400 28.2 +++ b/src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp Fri Apr 11 09:56:35 2008 -0400 28.3 @@ -32,49 +32,53 @@ 28.4 28.5 assert(Thread::current() == this, "caller must be current thread"); 28.6 assert(this->is_Java_thread(), "must be JavaThread"); 28.7 - 28.8 JavaThread* jt = (JavaThread *)this; 28.9 28.10 - // If we have a last_Java_frame, then we should use it even if 28.11 - // isInJava == true. It should be more reliable than ucontext info. 28.12 + // last_Java_frame is always walkable and safe use it if we have it 28.13 + 28.14 if (jt->has_last_Java_frame()) { 28.15 *fr_addr = jt->pd_last_frame(); 28.16 return true; 28.17 } 28.18 28.19 - // At this point, we don't have a last_Java_frame, so 28.20 - // we try to glean some information out of the ucontext 28.21 - // if we were running Java code when SIGPROF came in. 28.22 - if (isInJava) { 28.23 - ucontext_t* uc = (ucontext_t*) ucontext; 28.24 + ucontext_t* uc = (ucontext_t*) ucontext; 28.25 28.26 - intptr_t* ret_fp; 28.27 - intptr_t* ret_sp; 28.28 - ExtendedPC addr = os::Solaris::fetch_frame_from_ucontext(this, uc, 28.29 - &ret_sp, &ret_fp); 28.30 - if (addr.pc() == NULL || ret_sp == NULL ) { 28.31 - // ucontext wasn't useful 28.32 - return false; 28.33 - } 28.34 + // We always want to use the initial frame we create from the ucontext as 28.35 + // it certainly signals where we currently are. However that frame may not 28.36 + // be safe for calling sender. In that case if we have a last_Java_frame 28.37 + // then the forte walker will switch to that frame as the virtual sender 28.38 + // for the frame we create here which is not sender safe. 28.39 28.40 - frame ret_frame(ret_sp, ret_fp, addr.pc()); 28.41 - if (!ret_frame.safe_for_sender(jt)) { 28.42 -#ifdef COMPILER2 28.43 - frame ret_frame2(ret_sp, NULL, addr.pc()); 28.44 - if (!ret_frame2.safe_for_sender(jt)) { 28.45 - // nothing else to try if the frame isn't good 28.46 - return false; 28.47 - } 28.48 - ret_frame = ret_frame2; 28.49 -#else 28.50 - // nothing else to try if the frame isn't good 28.51 - return false; 28.52 -#endif /* COMPILER2 */ 28.53 - } 28.54 - *fr_addr = ret_frame; 28.55 - return true; 28.56 + intptr_t* ret_fp; 28.57 + intptr_t* ret_sp; 28.58 + ExtendedPC addr = os::Solaris::fetch_frame_from_ucontext(this, uc, &ret_sp, &ret_fp); 28.59 + 28.60 + // Something would really have to be screwed up to get a NULL pc 28.61 + 28.62 + if (addr.pc() == NULL ) { 28.63 + assert(false, "NULL pc from signal handler!"); 28.64 + return false; 28.65 + 28.66 } 28.67 28.68 - // nothing else to try 28.69 - return false; 28.70 + // If sp and fp are nonsense just leave them out 28.71 + 28.72 + if ((address)ret_sp >= jt->stack_base() || 28.73 + (address)ret_sp < jt->stack_base() - jt->stack_size() ) { 28.74 + 28.75 + ret_sp = NULL; 28.76 + ret_fp = NULL; 28.77 + } else { 28.78 + 28.79 + // sp is reasonable is fp reasonable? 28.80 + if ( (address)ret_fp >= jt->stack_base() || ret_fp < ret_sp) { 28.81 + ret_fp = NULL; 28.82 + } 28.83 + } 28.84 + 28.85 + frame ret_frame(ret_sp, ret_fp, addr.pc()); 28.86 + 28.87 + *fr_addr = ret_frame; 28.88 + return true; 28.89 + 28.90 }
29.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 29.2 +++ b/src/share/tools/hsdis/Makefile Fri Apr 11 09:56:35 2008 -0400 29.3 @@ -0,0 +1,135 @@ 29.4 +# 29.5 +# Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. 29.6 +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 29.7 +# 29.8 +# This code is free software; you can redistribute it and/or modify it 29.9 +# under the terms of the GNU General Public License version 2 only, as 29.10 +# published by the Free Software Foundation. 29.11 +# 29.12 +# This code is distributed in the hope that it will be useful, but WITHOUT 29.13 +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 29.14 +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 29.15 +# version 2 for more details (a copy is included in the LICENSE file that 29.16 +# accompanied this code). 29.17 +# 29.18 +# You should have received a copy of the GNU General Public License version 29.19 +# 2 along with this work; if not, write to the Free Software Foundation, 29.20 +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 29.21 +# 29.22 +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 29.23 +# CA 95054 USA or visit www.sun.com if you need additional information or 29.24 +# have any questions. 29.25 +# 29.26 +# 29.27 + 29.28 +# Single gnu makefile for solaris, linux and windows (windows requires mks or 29.29 +# cygwin). 29.30 + 29.31 +ifeq ($(BINUTILS),) 29.32 +# Pop all the way out of the workspace to look for binutils. 29.33 +# ...You probably want to override this setting. 29.34 +BINUTILS = $(shell cd ../../../../..;pwd)/binutils-2.17-$(LIBARCH) 29.35 +endif 29.36 + 29.37 +# Default arch; it is changed below as needed. 29.38 +ARCH = i386 29.39 +OS = $(shell uname) 29.40 + 29.41 +CPPFLAGS += -I$(BINUTILS)/include -I$(BINUTILS)/bfd 29.42 +CPPFLAGS += -DHOTSPOT_LIB_ARCH=\"$(LIBARCH)\" -DLIBARCH_$(LIBARCH) 29.43 +CPPFLAGS += -DHOTSPOT_OS=\"$(OS)\" -DOS_$(OS) 29.44 + 29.45 +## OS = SunOS ## 29.46 +ifeq ($(OS),SunOS) 29.47 +ARCH = $(shell uname -p) 29.48 +OS = solaris 29.49 +CC = cc 29.50 +CCFLAGS += -Kpic -g 29.51 +CCFLAGS/amd64 += -xarch=amd64 29.52 +CCFLAGS/sparcv9 += -xarch=v9 29.53 +CCFLAGS += $(CCFLAGS/$(LIBARCH)) 29.54 +DLDFLAGS += -G 29.55 +OUTFLAGS += -o $@ 29.56 +LIB_EXT = .so 29.57 +else 29.58 +## OS = Linux ## 29.59 +ifeq ($(OS),Linux) 29.60 +CPU = $(shell uname -m) 29.61 +ifeq ($(CPU),ia64) 29.62 +ARCH = ia64 29.63 +else 29.64 +ifeq ($(CPU),x86_64) 29.65 +CCFLAGS += -fPIC 29.66 +endif # x86_64 29.67 +endif # ia64 29.68 +OS = linux 29.69 +CC = gcc 29.70 +CCFLAGS += -O 29.71 +DLDFLAGS += -shared 29.72 +OUTFLAGS += -o $@ 29.73 +LIB_EXT = .so 29.74 +CPPFLAGS += -Iinclude -Iinclude/$(OS)_$(ARCH)/ 29.75 +## OS = Windows ## 29.76 +else # !SunOS, !Linux => Windows 29.77 +OS = win 29.78 +CC = cl 29.79 +#CPPFLAGS += /D"WIN32" /D"_WINDOWS" /D"DEBUG" /D"NDEBUG" 29.80 +CCFLAGS += /nologo /MD /W3 /WX /O2 /Fo$(@:.dll=.obj) /Gi- 29.81 +CCFLAGS += -Iinclude -Iinclude/gnu -Iinclude/$(OS)_$(ARCH) 29.82 +CCFLAGS += /D"HOTSPOT_LIB_ARCH=\"$(LIBARCH)\"" 29.83 +DLDFLAGS += /dll /subsystem:windows /incremental:no \ 29.84 + /export:decode_instruction 29.85 +OUTFLAGS += /link /out:$@ 29.86 +LIB_EXT = .dll 29.87 +endif # Linux 29.88 +endif # SunOS 29.89 + 29.90 +LIBARCH = $(ARCH) 29.91 +ifdef LP64 29.92 +LIBARCH64/sparc = sparcv9 29.93 +LIBARCH64/i386 = amd64 29.94 +LIBARCH64 = $(LIBARCH64/$(ARCH)) 29.95 +ifneq ($(LIBARCH64),) 29.96 +LIBARCH = $(LIBARCH64) 29.97 +endif # LIBARCH64/$(ARCH) 29.98 +endif # LP64 29.99 + 29.100 +TARGET_DIR = bin/$(OS) 29.101 +TARGET = $(TARGET_DIR)/hsdis-$(LIBARCH)$(LIB_EXT) 29.102 + 29.103 +SOURCE = hsdis.c 29.104 + 29.105 +LIBRARIES = $(BINUTILS)/bfd/libbfd.a \ 29.106 + $(BINUTILS)/opcodes/libopcodes.a \ 29.107 + $(BINUTILS)/libiberty/libiberty.a 29.108 + 29.109 +DEMO_TARGET = $(TARGET_DIR)/hsdis-demo-$(LIBARCH) 29.110 +DEMO_SOURCE = hsdis-demo.c 29.111 + 29.112 +.PHONY: all clean demo both 29.113 + 29.114 +all: $(TARGET) demo 29.115 + 29.116 +both: all all64 29.117 + 29.118 +%64: 29.119 + $(MAKE) LP64=1 ${@:%64=%} 29.120 + 29.121 +demo: $(TARGET) $(DEMO_TARGET) 29.122 + 29.123 +$(LIBRARIES): 29.124 + @echo "*** Please build binutils first; see ./README: ***" 29.125 + @sed < ./README '1,/__________/d' | head -20 29.126 + @echo "..."; exit 1 29.127 + 29.128 +$(TARGET): $(SOURCE) $(LIBS) $(LIBRARIES) $(TARGET_DIR) 29.129 + $(CC) $(OUTFLAGS) $(CPPFLAGS) $(CCFLAGS) $(SOURCE) $(DLDFLAGS) $(LIBRARIES) 29.130 + 29.131 +$(DEMO_TARGET): $(DEMO_SOURCE) $(TARGET) $(TARGET_DIR) 29.132 + $(CC) $(OUTFLAGS) $(CPPFLAGS) $(CCFLAGS) $(DEMO_SOURCE) $(LDFLAGS) 29.133 + 29.134 +$(TARGET_DIR): 29.135 + [ -d $@ ] || mkdir -p $@ 29.136 + 29.137 +clean: 29.138 + rm -rf $(TARGET_DIR)
30.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 30.2 +++ b/src/share/tools/hsdis/README Fri Apr 11 09:56:35 2008 -0400 30.3 @@ -0,0 +1,95 @@ 30.4 +Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. 30.5 +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 30.6 + 30.7 +This code is free software; you can redistribute it and/or modify it 30.8 +under the terms of the GNU General Public License version 2 only, as 30.9 +published by the Free Software Foundation. 30.10 + 30.11 +This code is distributed in the hope that it will be useful, but WITHOUT 30.12 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 30.13 +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 30.14 +version 2 for more details (a copy is included in the LICENSE file that 30.15 +accompanied this code). 30.16 + 30.17 +You should have received a copy of the GNU General Public License version 30.18 +2 along with this work; if not, write to the Free Software Foundation, 30.19 +Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 30.20 + 30.21 +Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 30.22 +CA 95054 USA or visit www.sun.com if you need additional information or 30.23 +have any questions. 30.24 + 30.25 +________________________________________________________________________ 30.26 + 30.27 +'hsdis': A HotSpot plugin for disassembling dynamically generated code. 30.28 + 30.29 +The files in this directory (Makefile, hsdis.[ch], hsdis-demo.c) 30.30 +are built independently of the HotSpot JVM. 30.31 + 30.32 +To use the plugin with a JVM, you need a new version that can load it. 30.33 +If the product mode of your JVM does not accept -XX:+PrintAssembly, 30.34 +you do not have a version that is new enough. 30.35 + 30.36 +* Building 30.37 + 30.38 +To build this project you need a build of Gnu binutils to link against. 30.39 +It is known to work with binutils 2.17. 30.40 + 30.41 +The makefile looks for this build in $BINUTILS, or (if that is not set), 30.42 +in .../binutils-2.17-$LIBARCH, where LIBARCH (as in HotSpot) is one of 30.43 +the jre subdirectory keywords i386, amd64, sparc, sparcv9, etc. 30.44 + 30.45 +To build Gnu binutils, first download a copy of the software: 30.46 + http://directory.fsf.org/project/binutils/ 30.47 + 30.48 +Unpack the binutils tarball into an empty directory: 30.49 + chdir ../../../../.. 30.50 + tar -xzf - < ../binutils-2.17.tar.gz 30.51 + mv binutils-2.17 binutils-2.17-i386 #or binutils-2.17-sparc 30.52 + cd binutils-2.17-i386 30.53 + 30.54 +From inside that directory, run configure and make: 30.55 + ( export CFLAGS='-fPIC' 30.56 + ./configure i386-pc-elf ) 30.57 + gnumake 30.58 + 30.59 +(Leave out or change the argument to configure if not on an i386 system.) 30.60 + 30.61 +Next, untar again into another empty directory for the LP64 version: 30.62 + chdir .. 30.63 + tar -xzf - < ../binutils-2.17.tar.gz 30.64 + mv binutils-2.17 binutils-2.17-amd64 #or binutils-2.17-sparcv9 30.65 + cd binutils-2.17-amd64 30.66 + 30.67 +From inside that directory, run configure for LP64 and make: 30.68 + ( export ac_cv_c_bigendian=no CFLAGS='-m64 -fPIC' LDFLAGS=-m64 30.69 + ./configure amd64-pc-elf ) 30.70 + gnumake 30.71 + 30.72 +The -fPIC option is needed because the generated code will be 30.73 +linked into the hsdid-$LIBARCH.so binary. If you miss the 30.74 +option, the JVM will fail to load the disassembler. 30.75 + 30.76 +You probably want two builds, one for 32 and one for 64 bits. 30.77 +To build the 64-bit variation of a platforn, add LP64=1 to 30.78 +the make command line for hsdis. 30.79 + 30.80 +So, go back to the hsdis project and build: 30.81 + chdir .../hsdis 30.82 + gnumake 30.83 + gnumake LP64=1 30.84 + 30.85 +* Installing 30.86 + 30.87 +Products are named like bin/$OS/hsdis-$LIBARCH.so. 30.88 +You can install them on your LD_LIBRARY_PATH, 30.89 +or inside of your JRE next to $LIBARCH/libjvm.so. 30.90 + 30.91 +Now test: 30.92 + export LD_LIBRARY_PATH .../hsdis/bin/solaris:$LD_LIBRARY_PATH 30.93 + dargs='-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly' 30.94 + dargs=$dargs' -XX:PrintAssemblyOptions=hsdis-print-bytes' 30.95 + java $dargs -Xbatch CompileCommand=print,*String.hashCode HelloWorld 30.96 + 30.97 +If the product mode of the JVM does not accept -XX:+PrintAssembly, 30.98 +you do not have a version new enough to use the hsdis plugin.
31.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 31.2 +++ b/src/share/tools/hsdis/hsdis-demo.c Fri Apr 11 09:56:35 2008 -0400 31.3 @@ -0,0 +1,223 @@ 31.4 +/* 31.5 + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. 31.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 31.7 + * 31.8 + * This code is free software; you can redistribute it and/or modify it 31.9 + * under the terms of the GNU General Public License version 2 only, as 31.10 + * published by the Free Software Foundation. 31.11 + * 31.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 31.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 31.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 31.15 + * version 2 for more details (a copy is included in the LICENSE file that 31.16 + * accompanied this code). 31.17 + * 31.18 + * You should have received a copy of the GNU General Public License version 31.19 + * 2 along with this work; if not, write to the Free Software Foundation, 31.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 31.21 + * 31.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 31.23 + * CA 95054 USA or visit www.sun.com if you need additional information or 31.24 + * have any questions. 31.25 + * 31.26 + */ 31.27 + 31.28 +/* hsdis-demo.c -- dump a range of addresses as native instructions 31.29 + This demonstrates the protocol required by the HotSpot PrintAssembly option. 31.30 +*/ 31.31 + 31.32 +#include "hsdis.h" 31.33 + 31.34 +#include "stdio.h" 31.35 +#include "stdlib.h" 31.36 +#include "string.h" 31.37 + 31.38 +void greet(const char*); 31.39 +void disassemble(void*, void*); 31.40 +void end_of_file(); 31.41 + 31.42 +const char* options = NULL; 31.43 +int raw = 0; 31.44 +int xml = 0; 31.45 + 31.46 +int main(int ac, char** av) { 31.47 + int greeted = 0; 31.48 + int i; 31.49 + for (i = 1; i < ac; i++) { 31.50 + const char* arg = av[i]; 31.51 + if (arg[0] == '-') { 31.52 + if (!strcmp(arg, "-xml")) 31.53 + xml ^= 1; 31.54 + else if (!strcmp(arg, "-raw")) 31.55 + raw ^= 1; 31.56 + else if (!strncmp(arg, "-options=", 9)) 31.57 + options = arg+9; 31.58 + else 31.59 + { printf("Usage: %s [-xml] [name...]\n"); exit(2); } 31.60 + continue; 31.61 + } 31.62 + greet(arg); 31.63 + greeted = 1; 31.64 + } 31.65 + if (!greeted) 31.66 + greet("world"); 31.67 + printf("...And now for something completely different:\n"); 31.68 + disassemble((void*) &main, (void*) &end_of_file); 31.69 + printf("Cheers!\n"); 31.70 +} 31.71 + 31.72 +void greet(const char* whom) { 31.73 + printf("Hello, %s!\n", whom); 31.74 +} 31.75 + 31.76 +void end_of_file() { } 31.77 + 31.78 +/* don't disassemble after this point... */ 31.79 + 31.80 +#include "dlfcn.h" 31.81 + 31.82 +#ifdef HOTSPOT_LIB_ARCH 31.83 +#define LIBARCH HOTSPOT_LIB_ARCH 31.84 +#endif 31.85 +#ifdef HOTSPOT_OS 31.86 +#define OS HOTSPOT_OS 31.87 +#endif 31.88 + 31.89 +#define DECODE_INSTRUCTIONS_NAME "decode_instructions" 31.90 +#define HSDIS_NAME "hsdis" 31.91 +static void* decode_instructions_pv = 0; 31.92 +static const char* hsdis_path[] = { 31.93 + HSDIS_NAME".so", 31.94 +#ifdef OS 31.95 + "bin/"OS"/"HSDIS_NAME".so", 31.96 +#endif 31.97 +#ifdef LIBARCH 31.98 + HSDIS_NAME"-"LIBARCH".so", 31.99 +#ifdef OS 31.100 + "bin/"OS"/"HSDIS_NAME"-"LIBARCH".so", 31.101 +#endif 31.102 +#endif 31.103 + NULL 31.104 +}; 31.105 + 31.106 +static const char* load_decode_instructions() { 31.107 + void* dllib = NULL; 31.108 + const char* *next_in_path = hsdis_path; 31.109 + while (1) { 31.110 + decode_instructions_pv = dlsym(dllib, DECODE_INSTRUCTIONS_NAME); 31.111 + if (decode_instructions_pv != NULL) 31.112 + return NULL; 31.113 + if (dllib != NULL) 31.114 + return "plugin does not defined "DECODE_INSTRUCTIONS_NAME; 31.115 + for (dllib = NULL; dllib == NULL; ) { 31.116 + const char* next_lib = (*next_in_path++); 31.117 + if (next_lib == NULL) 31.118 + return "cannot find plugin "HSDIS_NAME".so"; 31.119 + dllib = dlopen(next_lib, RTLD_LAZY); 31.120 + } 31.121 + } 31.122 +} 31.123 + 31.124 + 31.125 +static const char* lookup(void* addr) { 31.126 +#define CHECK_NAME(fn) \ 31.127 + if (addr == (void*) &fn) return #fn; 31.128 + 31.129 + CHECK_NAME(main); 31.130 + CHECK_NAME(greet); 31.131 + return NULL; 31.132 +} 31.133 + 31.134 +/* does the event match the tag, followed by a null, space, or slash? */ 31.135 +#define MATCH(event, tag) \ 31.136 + (!strncmp(event, tag, sizeof(tag)-1) && \ 31.137 + (!event[sizeof(tag)-1] || strchr(" /", event[sizeof(tag)-1]))) 31.138 + 31.139 + 31.140 +static const char event_cookie[] = "event_cookie"; /* demo placeholder */ 31.141 +static void* handle_event(void* cookie, const char* event, void* arg) { 31.142 +#define NS_DEMO "demo:" 31.143 + if (cookie != event_cookie) 31.144 + printf("*** bad event cookie %p != %p\n", cookie, event_cookie); 31.145 + 31.146 + if (xml) { 31.147 + /* We could almost do a printf(event, arg), 31.148 + but for the sake of a better demo, 31.149 + we dress the result up as valid XML. 31.150 + */ 31.151 + const char* fmt = strchr(event, ' '); 31.152 + int evlen = (fmt ? fmt - event : strlen(event)); 31.153 + if (!fmt) { 31.154 + if (event[0] != '/') { 31.155 + printf("<"NS_DEMO"%.*s>", evlen, event); 31.156 + } else { 31.157 + printf("</"NS_DEMO"%.*s>", evlen-1, event+1); 31.158 + } 31.159 + } else { 31.160 + if (event[0] != '/') { 31.161 + printf("<"NS_DEMO"%.*s", evlen, event); 31.162 + printf(fmt, arg); 31.163 + printf(">"); 31.164 + } else { 31.165 + printf("<"NS_DEMO"%.*s_done", evlen-1, event+1); 31.166 + printf(fmt, arg); 31.167 + printf("/></"NS_DEMO"%.*s>", evlen-1, event+1); 31.168 + } 31.169 + } 31.170 + } 31.171 + 31.172 + if (MATCH(event, "insn")) { 31.173 + const char* name = lookup(arg); 31.174 + if (name) printf("%s:\n", name); 31.175 + 31.176 + /* basic action for <insn>: */ 31.177 + printf(" %p\t", arg); 31.178 + 31.179 + } else if (MATCH(event, "/insn")) { 31.180 + /* basic action for </insn>: 31.181 + (none, plugin puts the newline for us 31.182 + */ 31.183 + 31.184 + } else if (MATCH(event, "mach")) { 31.185 + printf("Decoding for CPU '%s'\n", (char*) arg); 31.186 + 31.187 + } else if (MATCH(event, "addr")) { 31.188 + /* basic action for <addr/>: */ 31.189 + const char* name = lookup(arg); 31.190 + if (name) { 31.191 + printf("&%s (%p)", name, arg); 31.192 + /* return non-null to notify hsdis not to print the addr */ 31.193 + return arg; 31.194 + } 31.195 + } 31.196 + 31.197 + /* null return is always safe; can mean "I ignored it" */ 31.198 + return NULL; 31.199 +} 31.200 + 31.201 +#define fprintf_callback \ 31.202 + (decode_instructions_printf_callback_ftype)&fprintf 31.203 + 31.204 +void disassemble(void* from, void* to) { 31.205 + const char* err = load_decode_instructions(); 31.206 + if (err != NULL) { 31.207 + printf("%s: %s\n", err, dlerror()); 31.208 + exit(1); 31.209 + } 31.210 + printf("Decoding from %p to %p...\n", from, to); 31.211 + decode_instructions_ftype decode_instructions 31.212 + = (decode_instructions_ftype) decode_instructions_pv; 31.213 + void* res; 31.214 + if (raw && xml) { 31.215 + res = (*decode_instructions)(from, to, NULL, stdout, NULL, stdout, options); 31.216 + } else if (raw) { 31.217 + res = (*decode_instructions)(from, to, NULL, NULL, NULL, stdout, options); 31.218 + } else { 31.219 + res = (*decode_instructions)(from, to, 31.220 + handle_event, (void*) event_cookie, 31.221 + fprintf_callback, stdout, 31.222 + options); 31.223 + } 31.224 + if (res != to) 31.225 + printf("*** Result was %p!\n", res); 31.226 +}
32.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 32.2 +++ b/src/share/tools/hsdis/hsdis.c Fri Apr 11 09:56:35 2008 -0400 32.3 @@ -0,0 +1,499 @@ 32.4 +/* 32.5 + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. 32.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 32.7 + * 32.8 + * This code is free software; you can redistribute it and/or modify it 32.9 + * under the terms of the GNU General Public License version 2 only, as 32.10 + * published by the Free Software Foundation. 32.11 + * 32.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 32.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 32.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 32.15 + * version 2 for more details (a copy is included in the LICENSE file that 32.16 + * accompanied this code). 32.17 + * 32.18 + * You should have received a copy of the GNU General Public License version 32.19 + * 2 along with this work; if not, write to the Free Software Foundation, 32.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 32.21 + * 32.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 32.23 + * CA 95054 USA or visit www.sun.com if you need additional information or 32.24 + * have any questions. 32.25 + * 32.26 + */ 32.27 + 32.28 +/* hsdis.c -- dump a range of addresses as native instructions 32.29 + This implements the plugin protocol required by the 32.30 + HotSpot PrintAssembly option. 32.31 +*/ 32.32 + 32.33 +#include "hsdis.h" 32.34 + 32.35 +#include <sysdep.h> 32.36 +#include <libiberty.h> 32.37 +#include <bfd.h> 32.38 +#include <dis-asm.h> 32.39 + 32.40 +#ifndef bool 32.41 +#define bool int 32.42 +#define true 1 32.43 +#define false 0 32.44 +#endif /*bool*/ 32.45 + 32.46 +/* short names for stuff in hsdis.h */ 32.47 +typedef decode_instructions_event_callback_ftype event_callback_t; 32.48 +typedef decode_instructions_printf_callback_ftype printf_callback_t; 32.49 + 32.50 +/* disassemble_info.application_data object */ 32.51 +struct hsdis_app_data { 32.52 + /* the arguments to decode_instructions */ 32.53 + uintptr_t start; uintptr_t end; 32.54 + event_callback_t event_callback; void* event_stream; 32.55 + printf_callback_t printf_callback; void* printf_stream; 32.56 + bool losing; 32.57 + 32.58 + /* the architecture being disassembled */ 32.59 + const char* arch_name; 32.60 + const bfd_arch_info_type* arch_info; 32.61 + 32.62 + /* the disassembler we are going to use: */ 32.63 + disassembler_ftype dfn; 32.64 + struct disassemble_info dinfo; /* the actual struct! */ 32.65 + 32.66 + char mach_option[64]; 32.67 + char insn_options[256]; 32.68 +}; 32.69 + 32.70 +#define DECL_APP_DATA(dinfo) \ 32.71 + struct hsdis_app_data* app_data = (struct hsdis_app_data*) (dinfo)->application_data 32.72 + 32.73 +#define DECL_EVENT_CALLBACK(app_data) \ 32.74 + event_callback_t event_callback = (app_data)->event_callback; \ 32.75 + void* event_stream = (app_data)->event_stream 32.76 + 32.77 +#define DECL_PRINTF_CALLBACK(app_data) \ 32.78 + printf_callback_t printf_callback = (app_data)->printf_callback; \ 32.79 + void* printf_stream = (app_data)->printf_stream 32.80 + 32.81 + 32.82 +static void print_help(struct hsdis_app_data* app_data, 32.83 + const char* msg, const char* arg); 32.84 +static void setup_app_data(struct hsdis_app_data* app_data, 32.85 + const char* options); 32.86 +static const char* format_insn_close(const char* close, 32.87 + disassemble_info* dinfo, 32.88 + char* buf, size_t bufsize); 32.89 + 32.90 +void* 32.91 +#ifdef DLL_ENTRY 32.92 + DLL_ENTRY 32.93 +#endif 32.94 +decode_instructions(void* start_pv, void* end_pv, 32.95 + event_callback_t event_callback_arg, void* event_stream_arg, 32.96 + printf_callback_t printf_callback_arg, void* printf_stream_arg, 32.97 + const char* options) { 32.98 + struct hsdis_app_data app_data; 32.99 + memset(&app_data, 0, sizeof(app_data)); 32.100 + app_data.start = (uintptr_t) start_pv; 32.101 + app_data.end = (uintptr_t) end_pv; 32.102 + app_data.event_callback = event_callback_arg; 32.103 + app_data.event_stream = event_stream_arg; 32.104 + app_data.printf_callback = printf_callback_arg; 32.105 + app_data.printf_stream = printf_stream_arg; 32.106 + 32.107 + setup_app_data(&app_data, options); 32.108 + char buf[128]; 32.109 + 32.110 + { 32.111 + /* now reload everything from app_data: */ 32.112 + DECL_EVENT_CALLBACK(&app_data); 32.113 + DECL_PRINTF_CALLBACK(&app_data); 32.114 + uintptr_t start = app_data.start; 32.115 + uintptr_t end = app_data.end; 32.116 + uintptr_t p = start; 32.117 + 32.118 + (*event_callback)(event_stream, "insns", (void*)start); 32.119 + 32.120 + (*event_callback)(event_stream, "mach name='%s'", 32.121 + (void*) app_data.arch_info->printable_name); 32.122 + if (app_data.dinfo.bytes_per_line != 0) { 32.123 + (*event_callback)(event_stream, "format bytes-per-line='%p'/", 32.124 + (void*)(intptr_t) app_data.dinfo.bytes_per_line); 32.125 + } 32.126 + 32.127 + while (p < end && !app_data.losing) { 32.128 + (*event_callback)(event_stream, "insn", (void*) p); 32.129 + 32.130 + /* reset certain state, so we can read it with confidence */ 32.131 + app_data.dinfo.insn_info_valid = 0; 32.132 + app_data.dinfo.branch_delay_insns = 0; 32.133 + app_data.dinfo.data_size = 0; 32.134 + app_data.dinfo.insn_type = 0; 32.135 + 32.136 + int size = (*app_data.dfn)((bfd_vma) p, &app_data.dinfo); 32.137 + 32.138 + if (size > 0) p += size; 32.139 + else app_data.losing = true; 32.140 + 32.141 + const char* insn_close = format_insn_close("/insn", &app_data.dinfo, 32.142 + buf, sizeof(buf)); 32.143 + (*event_callback)(event_stream, insn_close, (void*) p); 32.144 + 32.145 + /* follow each complete insn by a nice newline */ 32.146 + (*printf_callback)(printf_stream, "\n"); 32.147 + } 32.148 + 32.149 + (*event_callback)(event_stream, "/insns", (void*) p); 32.150 + return (void*) p; 32.151 + } 32.152 +} 32.153 + 32.154 +/* take the address of the function, for luck, and also test the typedef: */ 32.155 +const decode_instructions_ftype decode_instructions_address = &decode_instructions; 32.156 + 32.157 +static const char* format_insn_close(const char* close, 32.158 + disassemble_info* dinfo, 32.159 + char* buf, size_t bufsize) { 32.160 + if (!dinfo->insn_info_valid) 32.161 + return close; 32.162 + enum dis_insn_type itype = dinfo->insn_type; 32.163 + int dsize = dinfo->data_size, delays = dinfo->branch_delay_insns; 32.164 + if ((itype == dis_nonbranch && (dsize | delays) == 0) 32.165 + || (strlen(close) + 3*20 > bufsize)) 32.166 + return close; 32.167 + 32.168 + const char* type = "unknown"; 32.169 + switch (itype) { 32.170 + case dis_nonbranch: type = NULL; break; 32.171 + case dis_branch: type = "branch"; break; 32.172 + case dis_condbranch: type = "condbranch"; break; 32.173 + case dis_jsr: type = "jsr"; break; 32.174 + case dis_condjsr: type = "condjsr"; break; 32.175 + case dis_dref: type = "dref"; break; 32.176 + case dis_dref2: type = "dref2"; break; 32.177 + } 32.178 + 32.179 + strcpy(buf, close); 32.180 + char* p = buf; 32.181 + if (type) sprintf(p += strlen(p), " type='%s'", type); 32.182 + if (dsize) sprintf(p += strlen(p), " dsize='%d'", dsize); 32.183 + if (delays) sprintf(p += strlen(p), " delay='%d'", delays); 32.184 + return buf; 32.185 +} 32.186 + 32.187 +/* handler functions */ 32.188 + 32.189 +static int 32.190 +hsdis_read_memory_func(bfd_vma memaddr, 32.191 + bfd_byte* myaddr, 32.192 + unsigned int length, 32.193 + struct disassemble_info* dinfo) { 32.194 + uintptr_t memaddr_p = (uintptr_t) memaddr; 32.195 + DECL_APP_DATA(dinfo); 32.196 + if (memaddr_p + length > app_data->end) { 32.197 + /* read is out of bounds */ 32.198 + return EIO; 32.199 + } else { 32.200 + memcpy(myaddr, (bfd_byte*) memaddr_p, length); 32.201 + return 0; 32.202 + } 32.203 +} 32.204 + 32.205 +static void 32.206 +hsdis_print_address_func(bfd_vma vma, struct disassemble_info* dinfo) { 32.207 + /* the actual value to print: */ 32.208 + void* addr_value = (void*) (uintptr_t) vma; 32.209 + DECL_APP_DATA(dinfo); 32.210 + DECL_EVENT_CALLBACK(app_data); 32.211 + 32.212 + /* issue the event: */ 32.213 + void* result = 32.214 + (*event_callback)(event_stream, "addr/", addr_value); 32.215 + if (result == NULL) { 32.216 + /* event declined */ 32.217 + generic_print_address(vma, dinfo); 32.218 + } 32.219 +} 32.220 + 32.221 + 32.222 +/* configuration */ 32.223 + 32.224 +static void set_optional_callbacks(struct hsdis_app_data* app_data); 32.225 +static void parse_caller_options(struct hsdis_app_data* app_data, 32.226 + const char* caller_options); 32.227 +static const char* native_arch_name(); 32.228 +static enum bfd_endian native_endian(); 32.229 +static const bfd_arch_info_type* find_arch_info(const char* arch_nane); 32.230 +static bfd* get_native_bfd(const bfd_arch_info_type* arch_info, 32.231 + /* to avoid malloc: */ 32.232 + bfd* empty_bfd, bfd_target* empty_xvec); 32.233 +static void init_disassemble_info_from_bfd(struct disassemble_info* dinfo, 32.234 + void *stream, 32.235 + fprintf_ftype fprintf_func, 32.236 + bfd* bfd, 32.237 + char* disassembler_options); 32.238 +static void parse_fake_insn(disassembler_ftype dfn, 32.239 + struct disassemble_info* dinfo); 32.240 + 32.241 +static void setup_app_data(struct hsdis_app_data* app_data, 32.242 + const char* caller_options) { 32.243 + /* Make reasonable defaults for null callbacks. 32.244 + A non-null stream for a null callback is assumed to be a FILE* for output. 32.245 + Events are rendered as XML. 32.246 + */ 32.247 + set_optional_callbacks(app_data); 32.248 + 32.249 + /* Look into caller_options for anything interesting. */ 32.250 + if (caller_options != NULL) 32.251 + parse_caller_options(app_data, caller_options); 32.252 + 32.253 + /* Discover which architecture we are going to disassemble. */ 32.254 + app_data->arch_name = &app_data->mach_option[0]; 32.255 + if (app_data->arch_name[0] == '\0') 32.256 + app_data->arch_name = native_arch_name(); 32.257 + app_data->arch_info = find_arch_info(app_data->arch_name); 32.258 + 32.259 + /* Make a fake bfd to hold the arch. and byteorder info. */ 32.260 + struct { 32.261 + bfd_target empty_xvec; 32.262 + bfd empty_bfd; 32.263 + } buf; 32.264 + bfd* native_bfd = get_native_bfd(app_data->arch_info, 32.265 + /* to avoid malloc: */ 32.266 + &buf.empty_bfd, &buf.empty_xvec); 32.267 + init_disassemble_info_from_bfd(&app_data->dinfo, 32.268 + app_data->printf_stream, 32.269 + app_data->printf_callback, 32.270 + native_bfd, 32.271 + app_data->insn_options); 32.272 + 32.273 + /* Finish linking together the various callback blocks. */ 32.274 + app_data->dinfo.application_data = (void*) app_data; 32.275 + app_data->dfn = disassembler(native_bfd); 32.276 + app_data->dinfo.print_address_func = hsdis_print_address_func; 32.277 + app_data->dinfo.read_memory_func = hsdis_read_memory_func; 32.278 + 32.279 + if (app_data->dfn == NULL) { 32.280 + const char* bad = app_data->arch_name; 32.281 + static bool complained; 32.282 + if (bad == &app_data->mach_option[0]) 32.283 + print_help(app_data, "bad mach=%s", bad); 32.284 + else if (!complained) 32.285 + print_help(app_data, "bad native mach=%s; please port hsdis to this platform", bad); 32.286 + complained = true; 32.287 + /* must bail out */ 32.288 + app_data->losing = true; 32.289 + return; 32.290 + } 32.291 + 32.292 + parse_fake_insn(app_data->dfn, &app_data->dinfo); 32.293 +} 32.294 + 32.295 + 32.296 +/* ignore all events, return a null */ 32.297 +static void* null_event_callback(void* ignore_stream, const char* ignore_event, void* arg) { 32.298 + return NULL; 32.299 +} 32.300 + 32.301 +/* print all events as XML markup */ 32.302 +static void* xml_event_callback(void* stream, const char* event, void* arg) { 32.303 + FILE* fp = (FILE*) stream; 32.304 +#define NS_PFX "dis:" 32.305 + if (event[0] != '/') { 32.306 + /* issue the tag, with or without a formatted argument */ 32.307 + fprintf(fp, "<"NS_PFX); 32.308 + fprintf(fp, event, arg); 32.309 + fprintf(fp, ">"); 32.310 + } else { 32.311 + ++event; /* skip slash */ 32.312 + const char* argp = strchr(event, ' '); 32.313 + if (argp == NULL) { 32.314 + /* no arguments; just issue the closing tag */ 32.315 + fprintf(fp, "</"NS_PFX"%s>", event); 32.316 + } else { 32.317 + /* split out the closing attributes as <dis:foo_done attr='val'/> */ 32.318 + int event_prefix = (argp - event); 32.319 + fprintf(fp, "<"NS_PFX"%.*s_done", event_prefix, event); 32.320 + fprintf(fp, argp, arg); 32.321 + fprintf(fp, "/></"NS_PFX"%.*s>", event_prefix, event); 32.322 + } 32.323 + } 32.324 + return NULL; 32.325 +} 32.326 + 32.327 +static void set_optional_callbacks(struct hsdis_app_data* app_data) { 32.328 + if (app_data->printf_callback == NULL) { 32.329 + int (*fprintf_callback)(FILE*, const char*, ...) = &fprintf; 32.330 + FILE* fprintf_stream = stdout; 32.331 + app_data->printf_callback = (printf_callback_t) fprintf_callback; 32.332 + if (app_data->printf_stream == NULL) 32.333 + app_data->printf_stream = (void*) fprintf_stream; 32.334 + } 32.335 + if (app_data->event_callback == NULL) { 32.336 + if (app_data->event_stream == NULL) 32.337 + app_data->event_callback = &null_event_callback; 32.338 + else 32.339 + app_data->event_callback = &xml_event_callback; 32.340 + } 32.341 + 32.342 +} 32.343 + 32.344 +static void parse_caller_options(struct hsdis_app_data* app_data, const char* caller_options) { 32.345 + char* iop_base = app_data->insn_options; 32.346 + char* iop_limit = iop_base + sizeof(app_data->insn_options) - 1; 32.347 + char* iop = iop_base; 32.348 + const char* p; 32.349 + for (p = caller_options; p != NULL; ) { 32.350 + const char* q = strchr(p, ','); 32.351 + size_t plen = (q == NULL) ? strlen(p) : ((q++) - p); 32.352 + if (plen == 4 && strncmp(p, "help", plen) == 0) { 32.353 + print_help(app_data, NULL, NULL); 32.354 + } else if (plen >= 5 && strncmp(p, "mach=", 5) == 0) { 32.355 + char* mach_option = app_data->mach_option; 32.356 + size_t mach_size = sizeof(app_data->mach_option); 32.357 + mach_size -= 1; /*leave room for the null*/ 32.358 + if (plen > mach_size) plen = mach_size; 32.359 + strncpy(mach_option, p, plen); 32.360 + mach_option[plen] = '\0'; 32.361 + } else if (plen > 6 && strncmp(p, "hsdis-", 6)) { 32.362 + // do not pass these to the next level 32.363 + } else { 32.364 + /* just copy it; {i386,sparc}-dis.c might like to see it */ 32.365 + if (iop > iop_base && iop < iop_limit) (*iop++) = ','; 32.366 + if (iop + plen > iop_limit) 32.367 + plen = iop_limit - iop; 32.368 + strncpy(iop, p, plen); 32.369 + iop += plen; 32.370 + } 32.371 + p = q; 32.372 + } 32.373 +} 32.374 + 32.375 +static void print_help(struct hsdis_app_data* app_data, 32.376 + const char* msg, const char* arg) { 32.377 + DECL_PRINTF_CALLBACK(app_data); 32.378 + if (msg != NULL) { 32.379 + (*printf_callback)(printf_stream, "hsdis: "); 32.380 + (*printf_callback)(printf_stream, msg, arg); 32.381 + (*printf_callback)(printf_stream, "\n"); 32.382 + } 32.383 + (*printf_callback)(printf_stream, "hsdis output options:\n"); 32.384 + if (printf_callback == (printf_callback_t) &fprintf) 32.385 + disassembler_usage((FILE*) printf_stream); 32.386 + else 32.387 + disassembler_usage(stderr); /* better than nothing */ 32.388 + (*printf_callback)(printf_stream, " mach=<arch> select disassembly mode\n"); 32.389 +#if defined(LIBARCH_i386) || defined(LIBARCH_amd64) 32.390 + (*printf_callback)(printf_stream, " mach=i386 select 32-bit mode\n"); 32.391 + (*printf_callback)(printf_stream, " mach=x86-64 select 64-bit mode\n"); 32.392 + (*printf_callback)(printf_stream, " suffix always print instruction suffix\n"); 32.393 +#endif 32.394 + (*printf_callback)(printf_stream, " help print this message\n"); 32.395 +} 32.396 + 32.397 + 32.398 +/* low-level bfd and arch stuff that binutils doesn't do for us */ 32.399 + 32.400 +static const bfd_arch_info_type* find_arch_info(const char* arch_name) { 32.401 + const bfd_arch_info_type* arch_info = bfd_scan_arch(arch_name); 32.402 + if (arch_info == NULL) { 32.403 + extern const bfd_arch_info_type bfd_default_arch_struct; 32.404 + arch_info = &bfd_default_arch_struct; 32.405 + } 32.406 + return arch_info; 32.407 +} 32.408 + 32.409 +static const char* native_arch_name() { 32.410 + const char* res = HOTSPOT_LIB_ARCH; 32.411 +#ifdef LIBARCH_amd64 32.412 + res = "i386:x86-64"; 32.413 +#endif 32.414 +#ifdef LIBARCH_sparc 32.415 + res = "sparc:v8plusb"; 32.416 +#endif 32.417 +#ifdef LIBARCH_sparc 32.418 + res = "sparc:v8plusb"; 32.419 +#endif 32.420 +#ifdef LIBARCH_sparcv9 32.421 + res = "sparc:v9b"; 32.422 +#endif 32.423 + if (res == NULL) 32.424 + res = "HOTSPOT_LIB_ARCH is not set in Makefile!"; 32.425 + return res; 32.426 +} 32.427 + 32.428 +static enum bfd_endian native_endian() { 32.429 + int32_t endian_test = 'x'; 32.430 + if (*(const char*) &endian_test == 'x') 32.431 + return BFD_ENDIAN_LITTLE; 32.432 + else 32.433 + return BFD_ENDIAN_BIG; 32.434 +} 32.435 + 32.436 +static bfd* get_native_bfd(const bfd_arch_info_type* arch_info, 32.437 + bfd* empty_bfd, bfd_target* empty_xvec) { 32.438 + memset(empty_bfd, 0, sizeof(*empty_bfd)); 32.439 + memset(empty_xvec, 0, sizeof(*empty_xvec)); 32.440 + empty_xvec->flavour = bfd_target_unknown_flavour; 32.441 + empty_xvec->byteorder = native_endian(); 32.442 + empty_bfd->xvec = empty_xvec; 32.443 + empty_bfd->arch_info = arch_info; 32.444 + return empty_bfd; 32.445 +} 32.446 + 32.447 +static int read_zero_data_only(bfd_vma ignore_p, 32.448 + bfd_byte* myaddr, unsigned int length, 32.449 + struct disassemble_info *ignore_info) { 32.450 + memset(myaddr, 0, length); 32.451 + return 0; 32.452 +} 32.453 +static int print_to_dev_null(void* ignore_stream, const char* ignore_format, ...) { 32.454 + return 0; 32.455 +} 32.456 + 32.457 +/* Prime the pump by running the selected disassembler on a null input. 32.458 + This forces the machine-specific disassembler to divulge invariant 32.459 + information like bytes_per_line. 32.460 + */ 32.461 +static void parse_fake_insn(disassembler_ftype dfn, 32.462 + struct disassemble_info* dinfo) { 32.463 + typedef int (*read_memory_ftype) 32.464 + (bfd_vma memaddr, bfd_byte *myaddr, unsigned int length, 32.465 + struct disassemble_info *info); 32.466 + read_memory_ftype read_memory_func = dinfo->read_memory_func; 32.467 + fprintf_ftype fprintf_func = dinfo->fprintf_func; 32.468 + 32.469 + dinfo->read_memory_func = &read_zero_data_only; 32.470 + dinfo->fprintf_func = &print_to_dev_null; 32.471 + (*dfn)(0, dinfo); 32.472 + 32.473 + // put it back: 32.474 + dinfo->read_memory_func = read_memory_func; 32.475 + dinfo->fprintf_func = fprintf_func; 32.476 +} 32.477 + 32.478 +static void init_disassemble_info_from_bfd(struct disassemble_info* dinfo, 32.479 + void *stream, 32.480 + fprintf_ftype fprintf_func, 32.481 + bfd* abfd, 32.482 + char* disassembler_options) { 32.483 + init_disassemble_info(dinfo, stream, fprintf_func); 32.484 + 32.485 + dinfo->flavour = bfd_get_flavour(abfd); 32.486 + dinfo->arch = bfd_get_arch(abfd); 32.487 + dinfo->mach = bfd_get_mach(abfd); 32.488 + dinfo->disassembler_options = disassembler_options; 32.489 + dinfo->octets_per_byte = bfd_octets_per_byte (abfd); 32.490 + dinfo->skip_zeroes = sizeof(void*) * 2; 32.491 + dinfo->skip_zeroes_at_end = sizeof(void*)-1; 32.492 + dinfo->disassembler_needs_relocs = FALSE; 32.493 + 32.494 + if (bfd_big_endian(abfd)) 32.495 + dinfo->display_endian = dinfo->endian = BFD_ENDIAN_BIG; 32.496 + else if (bfd_little_endian(abfd)) 32.497 + dinfo->display_endian = dinfo->endian = BFD_ENDIAN_LITTLE; 32.498 + else 32.499 + dinfo->endian = native_endian(); 32.500 + 32.501 + disassemble_init_for_target(dinfo); 32.502 +}
33.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 33.2 +++ b/src/share/tools/hsdis/hsdis.h Fri Apr 11 09:56:35 2008 -0400 33.3 @@ -0,0 +1,67 @@ 33.4 +/* 33.5 + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. 33.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 33.7 + * 33.8 + * This code is free software; you can redistribute it and/or modify it 33.9 + * under the terms of the GNU General Public License version 2 only, as 33.10 + * published by the Free Software Foundation. 33.11 + * 33.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 33.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 33.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 33.15 + * version 2 for more details (a copy is included in the LICENSE file that 33.16 + * accompanied this code). 33.17 + * 33.18 + * You should have received a copy of the GNU General Public License version 33.19 + * 2 along with this work; if not, write to the Free Software Foundation, 33.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 33.21 + * 33.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 33.23 + * CA 95054 USA or visit www.sun.com if you need additional information or 33.24 + * have any questions. 33.25 + * 33.26 + */ 33.27 + 33.28 +/* decode_instructions -- dump a range of addresses as native instructions 33.29 + This implements the protocol required by the HotSpot PrintAssembly option. 33.30 + 33.31 + The starting and ending addresses are within the current process's address space. 33.32 + 33.33 + The option string, if not empty, is interpreted by the disassembler implementation. 33.34 + 33.35 + The printf callback is 'fprintf' or any other workalike. 33.36 + It is called as (*printf_callback)(printf_stream, "some format...", some, format, args). 33.37 + 33.38 + The event callback receives an event tag (a string) and an argument (a void*). 33.39 + It is called as (*event_callback)(event_stream, "tag", arg). 33.40 + 33.41 + Events: 33.42 + <insn pc='%p'> begin an instruction, at a given location 33.43 + </insn pc='%d'> end an instruction, at a given location 33.44 + <addr value='%p'/> emit the symbolic value of an address 33.45 + 33.46 + A tag format is one of three basic forms: "tag", "/tag", "tag/", 33.47 + where tag is a simple identifier, signifying (as in XML) a element start, 33.48 + element end, and standalone element. (To render as XML, add angle brackets.) 33.49 +*/ 33.50 +extern 33.51 +#ifdef DLL_EXPORT 33.52 + DLL_EXPORT 33.53 +#endif 33.54 +void* decode_instructions(void* start, void* end, 33.55 + void* (*event_callback)(void*, const char*, void*), 33.56 + void* event_stream, 33.57 + int (*printf_callback)(void*, const char*, ...), 33.58 + void* printf_stream, 33.59 + const char* options); 33.60 + 33.61 +/* convenience typedefs */ 33.62 + 33.63 +typedef void* (*decode_instructions_event_callback_ftype) (void*, const char*, void*); 33.64 +typedef int (*decode_instructions_printf_callback_ftype) (void*, const char*, ...); 33.65 +typedef void* (*decode_instructions_ftype) (void* start, void* end, 33.66 + decode_instructions_event_callback_ftype event_callback, 33.67 + void* event_stream, 33.68 + decode_instructions_printf_callback_ftype printf_callback, 33.69 + void* printf_stream, 33.70 + const char* options);
34.1 --- a/src/share/vm/asm/codeBuffer.cpp Thu Apr 10 15:49:16 2008 -0400 34.2 +++ b/src/share/vm/asm/codeBuffer.cpp Fri Apr 11 09:56:35 2008 -0400 34.3 @@ -947,6 +947,7 @@ 34.4 if (_comments != NULL) { 34.5 CodeComment* c = _comments->find(offset); 34.6 while (c && c->offset() == offset) { 34.7 + stream->bol(); 34.8 stream->print(" ;; "); 34.9 stream->print_cr(c->comment()); 34.10 c = c->next();
35.1 --- a/src/share/vm/classfile/javaClasses.cpp Thu Apr 10 15:49:16 2008 -0400 35.2 +++ b/src/share/vm/classfile/javaClasses.cpp Fri Apr 11 09:56:35 2008 -0400 35.3 @@ -1015,7 +1015,6 @@ 35.4 typeArrayOop _bcis; 35.5 int _index; 35.6 bool _dirty; 35.7 - bool _done; 35.8 No_Safepoint_Verifier _nsv; 35.9 35.10 public: 35.11 @@ -1029,12 +1028,10 @@ 35.12 }; 35.13 35.14 // constructor for new backtrace 35.15 - BacktraceBuilder(TRAPS): _methods(NULL), _bcis(NULL), _head(NULL) { 35.16 + BacktraceBuilder(TRAPS): _methods(NULL), _bcis(NULL), _head(NULL), _dirty(false) { 35.17 expand(CHECK); 35.18 _backtrace = _head; 35.19 _index = 0; 35.20 - _dirty = false; 35.21 - _done = false; 35.22 } 35.23 35.24 void flush() {
36.1 --- a/src/share/vm/code/codeCache.hpp Thu Apr 10 15:49:16 2008 -0400 36.2 +++ b/src/share/vm/code/codeCache.hpp Fri Apr 11 09:56:35 2008 -0400 36.3 @@ -71,7 +71,22 @@ 36.4 // what you are doing) 36.5 static CodeBlob* find_blob_unsafe(void* start) { 36.6 CodeBlob* result = (CodeBlob*)_heap->find_start(start); 36.7 - assert(result == NULL || result->blob_contains((address)start), "found wrong CodeBlob"); 36.8 + // this assert is too strong because the heap code will return the 36.9 + // heapblock containing start. That block can often be larger than 36.10 + // the codeBlob itself. If you look up an address that is within 36.11 + // the heapblock but not in the codeBlob you will assert. 36.12 + // 36.13 + // Most things will not lookup such bad addresses. However 36.14 + // AsyncGetCallTrace can see intermediate frames and get that kind 36.15 + // of invalid address and so can a developer using hsfind. 36.16 + // 36.17 + // The more correct answer is to return NULL if blob_contains() returns 36.18 + // false. 36.19 + // assert(result == NULL || result->blob_contains((address)start), "found wrong CodeBlob"); 36.20 + 36.21 + if (result != NULL && !result->blob_contains((address)start)) { 36.22 + result = NULL; 36.23 + } 36.24 return result; 36.25 } 36.26
37.1 --- a/src/share/vm/code/nmethod.cpp Thu Apr 10 15:49:16 2008 -0400 37.2 +++ b/src/share/vm/code/nmethod.cpp Fri Apr 11 09:56:35 2008 -0400 37.3 @@ -707,7 +707,9 @@ 37.4 " entry points must be same for static methods and vice versa"); 37.5 } 37.6 37.7 - bool printnmethods = PrintNMethods || CompilerOracle::has_option_string(_method, "PrintNMethods"); 37.8 + bool printnmethods = PrintNMethods 37.9 + || CompilerOracle::should_print(_method) 37.10 + || CompilerOracle::has_option_string(_method, "PrintNMethods"); 37.11 if (printnmethods || PrintDebugInfo || PrintRelocations || PrintDependencies || PrintExceptionHandlers) { 37.12 print_nmethod(printnmethods); 37.13 } 37.14 @@ -798,7 +800,6 @@ 37.15 } 37.16 37.17 37.18 -#ifndef PRODUCT 37.19 void nmethod::print_nmethod(bool printmethod) { 37.20 ttyLocker ttyl; // keep the following output all in one block 37.21 if (xtty != NULL) { 37.22 @@ -831,7 +832,6 @@ 37.23 xtty->tail("print_nmethod"); 37.24 } 37.25 } 37.26 -#endif 37.27 37.28 37.29 void nmethod::set_version(int v) { 37.30 @@ -1870,6 +1870,7 @@ 37.31 } 37.32 } 37.33 37.34 +#endif // PRODUCT 37.35 37.36 // Printing operations 37.37 37.38 @@ -1948,6 +1949,14 @@ 37.39 oops_size()); 37.40 } 37.41 37.42 +void nmethod::print_code() { 37.43 + HandleMark hm; 37.44 + ResourceMark m; 37.45 + Disassembler::decode(this); 37.46 +} 37.47 + 37.48 + 37.49 +#ifndef PRODUCT 37.50 37.51 void nmethod::print_scopes() { 37.52 // Find the first pc desc for all scopes in the code and print it. 37.53 @@ -1979,13 +1988,6 @@ 37.54 } 37.55 37.56 37.57 -void nmethod::print_code() { 37.58 - HandleMark hm; 37.59 - ResourceMark m; 37.60 - Disassembler().decode(this); 37.61 -} 37.62 - 37.63 - 37.64 void nmethod::print_relocations() { 37.65 ResourceMark m; // in case methods get printed via the debugger 37.66 tty->print_cr("relocations:"); 37.67 @@ -2021,6 +2023,7 @@ 37.68 } 37.69 } 37.70 37.71 +#endif // PRODUCT 37.72 37.73 const char* nmethod::reloc_string_for(u_char* begin, u_char* end) { 37.74 RelocIterator iter(this, begin, end); 37.75 @@ -2055,7 +2058,6 @@ 37.76 return have_one ? "other" : NULL; 37.77 } 37.78 37.79 - 37.80 // Return a the last scope in (begin..end] 37.81 ScopeDesc* nmethod::scope_desc_in(address begin, address end) { 37.82 PcDesc* p = pc_desc_near(begin+1); 37.83 @@ -2078,29 +2080,26 @@ 37.84 address pc = base + om->offset(); 37.85 if (pc > begin) { 37.86 if (pc <= end) { 37.87 - st->fill_to(column); 37.88 - if (st == tty) { 37.89 - st->print("; OopMap "); 37.90 - om->print(); 37.91 - tty->cr(); 37.92 - } else { 37.93 - st->print_cr("; OopMap #%d offset:%d", i, om->offset()); 37.94 - } 37.95 + st->move_to(column); 37.96 + st->print("; "); 37.97 + om->print_on(st); 37.98 } 37.99 break; 37.100 } 37.101 } 37.102 } 37.103 + 37.104 + // Print any debug info present at this pc. 37.105 ScopeDesc* sd = scope_desc_in(begin, end); 37.106 if (sd != NULL) { 37.107 - st->fill_to(column); 37.108 + st->move_to(column); 37.109 if (sd->bci() == SynchronizationEntryBCI) { 37.110 st->print(";*synchronization entry"); 37.111 } else { 37.112 if (sd->method().is_null()) { 37.113 - tty->print("method is NULL"); 37.114 + st->print("method is NULL"); 37.115 } else if (sd->method()->is_native()) { 37.116 - tty->print("method is native"); 37.117 + st->print("method is native"); 37.118 } else { 37.119 address bcp = sd->method()->bcp_from(sd->bci()); 37.120 Bytecodes::Code bc = Bytecodes::java_code_at(bcp); 37.121 @@ -2137,13 +2136,13 @@ 37.122 } 37.123 } 37.124 } 37.125 - st->cr(); 37.126 + 37.127 // Print all scopes 37.128 for (;sd != NULL; sd = sd->sender()) { 37.129 - st->fill_to(column); 37.130 + st->move_to(column); 37.131 st->print("; -"); 37.132 if (sd->method().is_null()) { 37.133 - tty->print("method is NULL"); 37.134 + st->print("method is NULL"); 37.135 } else { 37.136 sd->method()->print_short_name(st); 37.137 } 37.138 @@ -2161,17 +2160,19 @@ 37.139 const char* str = reloc_string_for(begin, end); 37.140 if (str != NULL) { 37.141 if (sd != NULL) st->cr(); 37.142 - st->fill_to(column); 37.143 + st->move_to(column); 37.144 st->print("; {%s}", str); 37.145 } 37.146 int cont_offset = ImplicitExceptionTable(this).at(begin - instructions_begin()); 37.147 if (cont_offset != 0) { 37.148 - st->fill_to(column); 37.149 + st->move_to(column); 37.150 st->print("; implicit exception: dispatches to " INTPTR_FORMAT, instructions_begin() + cont_offset); 37.151 } 37.152 37.153 } 37.154 37.155 +#ifndef PRODUCT 37.156 + 37.157 void nmethod::print_value_on(outputStream* st) const { 37.158 print_on(st, "nmethod"); 37.159 }
38.1 --- a/src/share/vm/code/nmethod.hpp Thu Apr 10 15:49:16 2008 -0400 38.2 +++ b/src/share/vm/code/nmethod.hpp Fri Apr 11 09:56:35 2008 -0400 38.3 @@ -485,8 +485,8 @@ 38.4 void verify_interrupt_point(address interrupt_point); 38.5 38.6 // printing support 38.7 - void print() const PRODUCT_RETURN; 38.8 - void print_code() PRODUCT_RETURN; 38.9 + void print() const; 38.10 + void print_code(); 38.11 void print_relocations() PRODUCT_RETURN; 38.12 void print_pcs() PRODUCT_RETURN; 38.13 void print_scopes() PRODUCT_RETURN; 38.14 @@ -495,7 +495,7 @@ 38.15 void print_calls(outputStream* st) PRODUCT_RETURN; 38.16 void print_handler_table() PRODUCT_RETURN; 38.17 void print_nul_chk_table() PRODUCT_RETURN; 38.18 - void print_nmethod(bool print_code) PRODUCT_RETURN; 38.19 + void print_nmethod(bool print_code); 38.20 38.21 void print_on(outputStream* st, const char* title) const; 38.22 38.23 @@ -505,7 +505,7 @@ 38.24 void log_state_change(int state) const; 38.25 38.26 // Prints a comment for one native instruction (reloc info, pc desc) 38.27 - void print_code_comment_on(outputStream* st, int column, address begin, address end) PRODUCT_RETURN; 38.28 + void print_code_comment_on(outputStream* st, int column, address begin, address end); 38.29 static void print_statistics() PRODUCT_RETURN; 38.30 38.31 // Compiler task identification. Note that all OSR methods
39.1 --- a/src/share/vm/code/vmreg.cpp Thu Apr 10 15:49:16 2008 -0400 39.2 +++ b/src/share/vm/code/vmreg.cpp Fri Apr 11 09:56:35 2008 -0400 39.3 @@ -36,7 +36,6 @@ 39.4 // Register names 39.5 const char *VMRegImpl::regName[ConcreteRegisterImpl::number_of_registers]; 39.6 39.7 -#ifndef PRODUCT 39.8 void VMRegImpl::print_on(outputStream* st) const { 39.9 if( is_reg() ) { 39.10 assert( VMRegImpl::regName[value()], "" ); 39.11 @@ -48,4 +47,3 @@ 39.12 st->print("BAD!"); 39.13 } 39.14 } 39.15 -#endif // PRODUCT
40.1 --- a/src/share/vm/code/vmreg.hpp Thu Apr 10 15:49:16 2008 -0400 40.2 +++ b/src/share/vm/code/vmreg.hpp Fri Apr 11 09:56:35 2008 -0400 40.3 @@ -96,7 +96,7 @@ 40.4 40.5 intptr_t value() const {return (intptr_t) this; } 40.6 40.7 - void print_on(outputStream* st) const PRODUCT_RETURN; 40.8 + void print_on(outputStream* st) const; 40.9 void print() const { print_on(tty); } 40.10 40.11 // bias a stack slot. 40.12 @@ -156,22 +156,22 @@ 40.13 _first = ptr; 40.14 } 40.15 // Return true if single register, even if the pair is really just adjacent stack slots 40.16 - bool is_single_reg() { 40.17 + bool is_single_reg() const { 40.18 return (_first->is_valid()) && (_first->value() + 1 == _second->value()); 40.19 } 40.20 40.21 // Return true if single stack based "register" where the slot alignment matches input alignment 40.22 - bool is_adjacent_on_stack(int alignment) { 40.23 + bool is_adjacent_on_stack(int alignment) const { 40.24 return (_first->is_stack() && (_first->value() + 1 == _second->value()) && ((_first->value() & (alignment-1)) == 0)); 40.25 } 40.26 40.27 // Return true if single stack based "register" where the slot alignment matches input alignment 40.28 - bool is_adjacent_aligned_on_stack(int alignment) { 40.29 + bool is_adjacent_aligned_on_stack(int alignment) const { 40.30 return (_first->is_stack() && (_first->value() + 1 == _second->value()) && ((_first->value() & (alignment-1)) == 0)); 40.31 } 40.32 40.33 // Return true if single register but adjacent stack slots do not count 40.34 - bool is_single_phys_reg() { 40.35 + bool is_single_phys_reg() const { 40.36 return (_first->is_reg() && (_first->value() + 1 == _second->value())); 40.37 } 40.38
41.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 41.2 +++ b/src/share/vm/compiler/disassembler.cpp Fri Apr 11 09:56:35 2008 -0400 41.3 @@ -0,0 +1,443 @@ 41.4 +/* 41.5 + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. 41.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 41.7 + * 41.8 + * This code is free software; you can redistribute it and/or modify it 41.9 + * under the terms of the GNU General Public License version 2 only, as 41.10 + * published by the Free Software Foundation. 41.11 + * 41.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 41.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 41.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 41.15 + * version 2 for more details (a copy is included in the LICENSE file that 41.16 + * accompanied this code). 41.17 + * 41.18 + * You should have received a copy of the GNU General Public License version 41.19 + * 2 along with this work; if not, write to the Free Software Foundation, 41.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 41.21 + * 41.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 41.23 + * CA 95054 USA or visit www.sun.com if you need additional information or 41.24 + * have any questions. 41.25 + * 41.26 + */ 41.27 + 41.28 +# include "incls/_precompiled.incl" 41.29 +# include "incls/_disassembler.cpp.incl" 41.30 + 41.31 +void* Disassembler::_library = NULL; 41.32 +bool Disassembler::_tried_to_load_library = false; 41.33 + 41.34 +// This routine is in the shared library: 41.35 +Disassembler::decode_func Disassembler::_decode_instructions = NULL; 41.36 + 41.37 +static const char hsdis_library_name[] = "hsdis-"HOTSPOT_LIB_ARCH; 41.38 +static const char decode_instructions_name[] = "decode_instructions"; 41.39 + 41.40 +#define COMMENT_COLUMN 40 LP64_ONLY(+8) /*could be an option*/ 41.41 +#define BYTES_COMMENT ";..." /* funky byte display comment */ 41.42 + 41.43 +bool Disassembler::load_library() { 41.44 + if (_decode_instructions != NULL) { 41.45 + // Already succeeded. 41.46 + return true; 41.47 + } 41.48 + if (_tried_to_load_library) { 41.49 + // Do not try twice. 41.50 + // To force retry in debugger: assign _tried_to_load_library=0 41.51 + return false; 41.52 + } 41.53 + // Try to load it. 41.54 + char ebuf[1024]; 41.55 + char buf[JVM_MAXPATHLEN]; 41.56 + os::jvm_path(buf, sizeof(buf)); 41.57 + int jvm_offset = -1; 41.58 + { 41.59 + // Match "jvm[^/]*" in jvm_path. 41.60 + const char* base = buf; 41.61 + const char* p = strrchr(buf, '/'); 41.62 + p = strstr(p ? p : base, "jvm"); 41.63 + if (p != NULL) jvm_offset = p - base; 41.64 + } 41.65 + if (jvm_offset >= 0) { 41.66 + // Find the disassembler next to libjvm.so. 41.67 + strcpy(&buf[jvm_offset], hsdis_library_name); 41.68 + strcat(&buf[jvm_offset], os::dll_file_extension()); 41.69 + _library = hpi::dll_load(buf, ebuf, sizeof ebuf); 41.70 + } 41.71 + if (_library == NULL) { 41.72 + // Try a free-floating lookup. 41.73 + strcpy(&buf[0], hsdis_library_name); 41.74 + strcat(&buf[0], os::dll_file_extension()); 41.75 + _library = hpi::dll_load(buf, ebuf, sizeof ebuf); 41.76 + } 41.77 + if (_library != NULL) { 41.78 + _decode_instructions = CAST_TO_FN_PTR(Disassembler::decode_func, 41.79 + hpi::dll_lookup(_library, decode_instructions_name)); 41.80 + } 41.81 + _tried_to_load_library = true; 41.82 + if (_decode_instructions == NULL) { 41.83 + tty->print_cr("Could not load %s; %s; %s", buf, 41.84 + ((_library != NULL) 41.85 + ? "entry point is missing" 41.86 + : (WizardMode || PrintMiscellaneous) 41.87 + ? (const char*)ebuf 41.88 + : "library not loadable"), 41.89 + "PrintAssembly is disabled"); 41.90 + return false; 41.91 + } 41.92 + 41.93 + // Success. 41.94 + tty->print_cr("Loaded disassembler from %s", buf); 41.95 + return true; 41.96 +} 41.97 + 41.98 + 41.99 +class decode_env { 41.100 + private: 41.101 + nmethod* _nm; 41.102 + CodeBlob* _code; 41.103 + outputStream* _output; 41.104 + address _start, _end; 41.105 + 41.106 + char _option_buf[512]; 41.107 + char _print_raw; 41.108 + bool _print_pc; 41.109 + bool _print_bytes; 41.110 + address _cur_insn; 41.111 + int _total_ticks; 41.112 + int _bytes_per_line; // arch-specific formatting option 41.113 + 41.114 + static bool match(const char* event, const char* tag) { 41.115 + size_t taglen = strlen(tag); 41.116 + if (strncmp(event, tag, taglen) != 0) 41.117 + return false; 41.118 + char delim = event[taglen]; 41.119 + return delim == '\0' || delim == ' ' || delim == '/' || delim == '='; 41.120 + } 41.121 + 41.122 + void collect_options(const char* p) { 41.123 + if (p == NULL || p[0] == '\0') return; 41.124 + size_t opt_so_far = strlen(_option_buf); 41.125 + if (opt_so_far + 1 + strlen(p) + 1 > sizeof(_option_buf)) return; 41.126 + char* fillp = &_option_buf[opt_so_far]; 41.127 + if (opt_so_far > 0) *fillp++ = ','; 41.128 + strcat(fillp, p); 41.129 + // replace white space by commas: 41.130 + char* q = fillp; 41.131 + while ((q = strpbrk(q, " \t\n")) != NULL) 41.132 + *q++ = ','; 41.133 + // Note that multiple PrintAssemblyOptions flags accumulate with \n, 41.134 + // which we want to be changed to a comma... 41.135 + } 41.136 + 41.137 + void print_insn_labels(); 41.138 + void print_insn_bytes(address pc0, address pc); 41.139 + void print_address(address value); 41.140 + 41.141 + public: 41.142 + decode_env(CodeBlob* code, outputStream* output); 41.143 + 41.144 + address decode_instructions(address start, address end); 41.145 + 41.146 + void start_insn(address pc) { 41.147 + _cur_insn = pc; 41.148 + output()->bol(); 41.149 + print_insn_labels(); 41.150 + } 41.151 + 41.152 + void end_insn(address pc) { 41.153 + address pc0 = cur_insn(); 41.154 + outputStream* st = output(); 41.155 + if (_print_bytes && pc > pc0) 41.156 + print_insn_bytes(pc0, pc); 41.157 + if (_nm != NULL) 41.158 + _nm->print_code_comment_on(st, COMMENT_COLUMN, pc0, pc); 41.159 + 41.160 + // Output pc bucket ticks if we have any 41.161 + if (total_ticks() != 0) { 41.162 + address bucket_pc = FlatProfiler::bucket_start_for(pc); 41.163 + if (bucket_pc != NULL && bucket_pc > pc0 && bucket_pc <= pc) { 41.164 + int bucket_count = FlatProfiler::bucket_count_for(pc0); 41.165 + if (bucket_count != 0) { 41.166 + st->bol(); 41.167 + st->print_cr("%3.1f%% [%d]", bucket_count*100.0/total_ticks(), bucket_count); 41.168 + } 41.169 + } 41.170 + } 41.171 + } 41.172 + 41.173 + address handle_event(const char* event, address arg); 41.174 + 41.175 + outputStream* output() { return _output; } 41.176 + address cur_insn() { return _cur_insn; } 41.177 + int total_ticks() { return _total_ticks; } 41.178 + void set_total_ticks(int n) { _total_ticks = n; } 41.179 + const char* options() { return _option_buf; } 41.180 +}; 41.181 + 41.182 +decode_env::decode_env(CodeBlob* code, outputStream* output) { 41.183 + memset(this, 0, sizeof(*this)); 41.184 + _output = output ? output : tty; 41.185 + _code = code; 41.186 + if (code != NULL && code->is_nmethod()) 41.187 + _nm = (nmethod*) code; 41.188 + 41.189 + // by default, output pc but not bytes: 41.190 + _print_pc = true; 41.191 + _print_bytes = false; 41.192 + _bytes_per_line = Disassembler::pd_instruction_alignment(); 41.193 + 41.194 + // parse the global option string: 41.195 + collect_options(Disassembler::pd_cpu_opts()); 41.196 + collect_options(PrintAssemblyOptions); 41.197 + 41.198 + if (strstr(options(), "hsdis-")) { 41.199 + if (strstr(options(), "hsdis-print-raw")) 41.200 + _print_raw = (strstr(options(), "xml") ? 2 : 1); 41.201 + if (strstr(options(), "hsdis-print-pc")) 41.202 + _print_pc = !_print_pc; 41.203 + if (strstr(options(), "hsdis-print-bytes")) 41.204 + _print_bytes = !_print_bytes; 41.205 + } 41.206 + if (strstr(options(), "help")) { 41.207 + tty->print_cr("PrintAssemblyOptions help:"); 41.208 + tty->print_cr(" hsdis-print-raw test plugin by requesting raw output"); 41.209 + tty->print_cr(" hsdis-print-raw-xml test plugin by requesting raw xml"); 41.210 + tty->print_cr(" hsdis-print-pc turn off PC printing (on by default)"); 41.211 + tty->print_cr(" hsdis-print-bytes turn on instruction byte output"); 41.212 + tty->print_cr("combined options: %s", options()); 41.213 + } 41.214 +} 41.215 + 41.216 +address decode_env::handle_event(const char* event, address arg) { 41.217 + if (match(event, "insn")) { 41.218 + start_insn(arg); 41.219 + } else if (match(event, "/insn")) { 41.220 + end_insn(arg); 41.221 + } else if (match(event, "addr")) { 41.222 + if (arg != NULL) { 41.223 + print_address(arg); 41.224 + return arg; 41.225 + } 41.226 + } else if (match(event, "mach")) { 41.227 + output()->print_cr("[Disassembling for mach='%s']", arg); 41.228 + } else if (match(event, "format bytes-per-line")) { 41.229 + _bytes_per_line = (int) (intptr_t) arg; 41.230 + } else { 41.231 + // ignore unrecognized markup 41.232 + } 41.233 + return NULL; 41.234 +} 41.235 + 41.236 +// called by the disassembler to print out jump targets and data addresses 41.237 +void decode_env::print_address(address adr) { 41.238 + outputStream* st = _output; 41.239 + 41.240 + if (adr == NULL) { 41.241 + st->print("NULL"); 41.242 + return; 41.243 + } 41.244 + 41.245 + int small_num = (int)(intptr_t)adr; 41.246 + if ((intptr_t)adr == (intptr_t)small_num 41.247 + && -1 <= small_num && small_num <= 9) { 41.248 + st->print("%d", small_num); 41.249 + return; 41.250 + } 41.251 + 41.252 + if (Universe::is_fully_initialized()) { 41.253 + if (StubRoutines::contains(adr)) { 41.254 + StubCodeDesc* desc = StubCodeDesc::desc_for(adr); 41.255 + if (desc == NULL) 41.256 + desc = StubCodeDesc::desc_for(adr + frame::pc_return_offset); 41.257 + if (desc != NULL) { 41.258 + st->print("Stub::%s", desc->name()); 41.259 + if (desc->begin() != adr) 41.260 + st->print("%+d 0x%p",adr - desc->begin(), adr); 41.261 + else if (WizardMode) st->print(" " INTPTR_FORMAT, adr); 41.262 + return; 41.263 + } 41.264 + st->print("Stub::<unknown> " INTPTR_FORMAT, adr); 41.265 + return; 41.266 + } 41.267 + 41.268 + BarrierSet* bs = Universe::heap()->barrier_set(); 41.269 + if (bs->kind() == BarrierSet::CardTableModRef && 41.270 + adr == (address)((CardTableModRefBS*)(bs))->byte_map_base) { 41.271 + st->print("word_map_base"); 41.272 + if (WizardMode) st->print(" " INTPTR_FORMAT, (intptr_t)adr); 41.273 + return; 41.274 + } 41.275 + 41.276 + oop obj; 41.277 + if (_nm != NULL 41.278 + && (obj = _nm->embeddedOop_at(cur_insn())) != NULL 41.279 + && (address) obj == adr) { 41.280 + obj->print_value_on(st); 41.281 + return; 41.282 + } 41.283 + } 41.284 + 41.285 + // Fall through to a simple numeral. 41.286 + st->print(INTPTR_FORMAT, (intptr_t)adr); 41.287 +} 41.288 + 41.289 +void decode_env::print_insn_labels() { 41.290 + address p = cur_insn(); 41.291 + outputStream* st = output(); 41.292 + nmethod* nm = _nm; 41.293 + if (nm != NULL) { 41.294 + if (p == nm->entry_point()) st->print_cr("[Entry Point]"); 41.295 + if (p == nm->verified_entry_point()) st->print_cr("[Verified Entry Point]"); 41.296 + if (p == nm->exception_begin()) st->print_cr("[Exception Handler]"); 41.297 + if (p == nm->stub_begin()) st->print_cr("[Stub Code]"); 41.298 + if (p == nm->consts_begin()) st->print_cr("[Constants]"); 41.299 + } 41.300 + CodeBlob* cb = _code; 41.301 + if (cb != NULL) { 41.302 + cb->print_block_comment(st, (intptr_t)(p - cb->instructions_begin())); 41.303 + } 41.304 + if (_print_pc) { 41.305 + st->print(" " INTPTR_FORMAT ": ", (intptr_t) p); 41.306 + } 41.307 +} 41.308 + 41.309 +void decode_env::print_insn_bytes(address pc, address pc_limit) { 41.310 + outputStream* st = output(); 41.311 + size_t incr = 1; 41.312 + size_t perline = _bytes_per_line; 41.313 + if ((size_t) Disassembler::pd_instruction_alignment() >= sizeof(int) 41.314 + && !((uintptr_t)pc % sizeof(int)) 41.315 + && !((uintptr_t)pc_limit % sizeof(int))) { 41.316 + incr = sizeof(int); 41.317 + if (perline % incr) perline += incr - (perline % incr); 41.318 + } 41.319 + while (pc < pc_limit) { 41.320 + // tab to the desired column: 41.321 + st->move_to(COMMENT_COLUMN); 41.322 + address pc0 = pc; 41.323 + address pc1 = pc + perline; 41.324 + if (pc1 > pc_limit) pc1 = pc_limit; 41.325 + for (; pc < pc1; pc += incr) { 41.326 + if (pc == pc0) 41.327 + st->print(BYTES_COMMENT); 41.328 + else if ((uint)(pc - pc0) % sizeof(int) == 0) 41.329 + st->print(" "); // put out a space on word boundaries 41.330 + if (incr == sizeof(int)) 41.331 + st->print("%08lx", *(int*)pc); 41.332 + else st->print("%02x", (*pc)&0xFF); 41.333 + } 41.334 + st->cr(); 41.335 + } 41.336 +} 41.337 + 41.338 + 41.339 +static void* event_to_env(void* env_pv, const char* event, void* arg) { 41.340 + decode_env* env = (decode_env*) env_pv; 41.341 + return env->handle_event(event, (address) arg); 41.342 +} 41.343 + 41.344 +static int printf_to_env(void* env_pv, const char* format, ...) { 41.345 + decode_env* env = (decode_env*) env_pv; 41.346 + outputStream* st = env->output(); 41.347 + size_t flen = strlen(format); 41.348 + const char* raw = NULL; 41.349 + if (flen == 0) return 0; 41.350 + if (flen == 1 && format[0] == '\n') { st->bol(); return 1; } 41.351 + if (flen < 2 || 41.352 + strchr(format, '%') == NULL) { 41.353 + raw = format; 41.354 + } else if (format[0] == '%' && format[1] == '%' && 41.355 + strchr(format+2, '%') == NULL) { 41.356 + // happens a lot on machines with names like %foo 41.357 + flen--; 41.358 + raw = format+1; 41.359 + } 41.360 + if (raw != NULL) { 41.361 + st->print_raw(raw, (int) flen); 41.362 + return (int) flen; 41.363 + } 41.364 + va_list ap; 41.365 + va_start(ap, format); 41.366 + julong cnt0 = st->count(); 41.367 + st->vprint(format, ap); 41.368 + julong cnt1 = st->count(); 41.369 + va_end(ap); 41.370 + return (int)(cnt1 - cnt0); 41.371 +} 41.372 + 41.373 +address decode_env::decode_instructions(address start, address end) { 41.374 + _start = start; _end = end; 41.375 + 41.376 + assert((((intptr_t)start | (intptr_t)end) % Disassembler::pd_instruction_alignment() == 0), "misaligned insn addr"); 41.377 + 41.378 + const int show_bytes = false; // for disassembler debugging 41.379 + 41.380 + //_version = Disassembler::pd_cpu_version(); 41.381 + 41.382 + if (!Disassembler::can_decode()) { 41.383 + return NULL; 41.384 + } 41.385 + 41.386 + // decode a series of instructions and return the end of the last instruction 41.387 + 41.388 + if (_print_raw) { 41.389 + // Print whatever the library wants to print, w/o fancy callbacks. 41.390 + // This is mainly for debugging the library itself. 41.391 + FILE* out = stdout; 41.392 + FILE* xmlout = (_print_raw > 1 ? out : NULL); 41.393 + return (address) 41.394 + (*Disassembler::_decode_instructions)(start, end, 41.395 + NULL, (void*) xmlout, 41.396 + NULL, (void*) out, 41.397 + options()); 41.398 + } 41.399 + 41.400 + return (address) 41.401 + (*Disassembler::_decode_instructions)(start, end, 41.402 + &event_to_env, (void*) this, 41.403 + &printf_to_env, (void*) this, 41.404 + options()); 41.405 +} 41.406 + 41.407 + 41.408 +void Disassembler::decode(CodeBlob* cb, outputStream* st) { 41.409 + if (!load_library()) return; 41.410 + decode_env env(cb, st); 41.411 + env.output()->print_cr("Decoding CodeBlob " INTPTR_FORMAT, cb); 41.412 + env.decode_instructions(cb->instructions_begin(), cb->instructions_end()); 41.413 +} 41.414 + 41.415 + 41.416 +void Disassembler::decode(address start, address end, outputStream* st) { 41.417 + if (!load_library()) return; 41.418 + decode_env env(CodeCache::find_blob_unsafe(start), st); 41.419 + env.decode_instructions(start, end); 41.420 +} 41.421 + 41.422 +void Disassembler::decode(nmethod* nm, outputStream* st) { 41.423 + if (!load_library()) return; 41.424 + decode_env env(nm, st); 41.425 + env.output()->print_cr("Decoding compiled method " INTPTR_FORMAT ":", nm); 41.426 + env.output()->print_cr("Code:"); 41.427 + 41.428 + unsigned char* p = nm->instructions_begin(); 41.429 + unsigned char* end = nm->instructions_end(); 41.430 + 41.431 + // If there has been profiling, print the buckets. 41.432 + if (FlatProfiler::bucket_start_for(p) != NULL) { 41.433 + unsigned char* p1 = p; 41.434 + int total_bucket_count = 0; 41.435 + while (p1 < end) { 41.436 + unsigned char* p0 = p1; 41.437 + p1 += pd_instruction_alignment(); 41.438 + address bucket_pc = FlatProfiler::bucket_start_for(p1); 41.439 + if (bucket_pc != NULL && bucket_pc > p0 && bucket_pc <= p1) 41.440 + total_bucket_count += FlatProfiler::bucket_count_for(p0); 41.441 + } 41.442 + env.set_total_ticks(total_bucket_count); 41.443 + } 41.444 + 41.445 + env.decode_instructions(p, end); 41.446 +}
42.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 42.2 +++ b/src/share/vm/compiler/disassembler.hpp Fri Apr 11 09:56:35 2008 -0400 42.3 @@ -0,0 +1,59 @@ 42.4 +/* 42.5 + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. 42.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 42.7 + * 42.8 + * This code is free software; you can redistribute it and/or modify it 42.9 + * under the terms of the GNU General Public License version 2 only, as 42.10 + * published by the Free Software Foundation. 42.11 + * 42.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 42.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 42.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 42.15 + * version 2 for more details (a copy is included in the LICENSE file that 42.16 + * accompanied this code). 42.17 + * 42.18 + * You should have received a copy of the GNU General Public License version 42.19 + * 2 along with this work; if not, write to the Free Software Foundation, 42.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 42.21 + * 42.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 42.23 + * CA 95054 USA or visit www.sun.com if you need additional information or 42.24 + * have any questions. 42.25 + * 42.26 + */ 42.27 + 42.28 +class decode_env; 42.29 + 42.30 +// The disassembler prints out assembly code annotated 42.31 +// with Java specific information. 42.32 + 42.33 +class Disassembler { 42.34 + friend class decode_env; 42.35 + private: 42.36 + // this is the type of the dll entry point: 42.37 + typedef void* (*decode_func)(void* start, void* end, 42.38 + void* (*event_callback)(void*, const char*, void*), 42.39 + void* event_stream, 42.40 + int (*printf_callback)(void*, const char*, ...), 42.41 + void* printf_stream, 42.42 + const char* options); 42.43 + // points to the library. 42.44 + static void* _library; 42.45 + // bailout 42.46 + static bool _tried_to_load_library; 42.47 + // points to the decode function. 42.48 + static decode_func _decode_instructions; 42.49 + // tries to load library and return whether it succedded. 42.50 + static bool load_library(); 42.51 + 42.52 + // Machine dependent stuff 42.53 + #include "incls/_disassembler_pd.hpp.incl" 42.54 + 42.55 + public: 42.56 + static bool can_decode() { 42.57 + return (_decode_instructions != NULL) || load_library(); 42.58 + } 42.59 + static void decode(CodeBlob *cb, outputStream* st = NULL); 42.60 + static void decode(nmethod* nm, outputStream* st = NULL); 42.61 + static void decode(address begin, address end, outputStream* st = NULL); 42.62 +};
43.1 --- a/src/share/vm/compiler/disassemblerEnv.hpp Thu Apr 10 15:49:16 2008 -0400 43.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 43.3 @@ -1,35 +0,0 @@ 43.4 -/* 43.5 - * Copyright 1997-2002 Sun Microsystems, Inc. All Rights Reserved. 43.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 43.7 - * 43.8 - * This code is free software; you can redistribute it and/or modify it 43.9 - * under the terms of the GNU General Public License version 2 only, as 43.10 - * published by the Free Software Foundation. 43.11 - * 43.12 - * This code is distributed in the hope that it will be useful, but WITHOUT 43.13 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 43.14 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 43.15 - * version 2 for more details (a copy is included in the LICENSE file that 43.16 - * accompanied this code). 43.17 - * 43.18 - * You should have received a copy of the GNU General Public License version 43.19 - * 2 along with this work; if not, write to the Free Software Foundation, 43.20 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 43.21 - * 43.22 - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 43.23 - * CA 95054 USA or visit www.sun.com if you need additional information or 43.24 - * have any questions. 43.25 - * 43.26 - */ 43.27 - 43.28 -// Call-back interface for external disassembler 43.29 -class DisassemblerEnv { 43.30 - public: 43.31 - // printing 43.32 - virtual void print_label(intptr_t value) = 0; 43.33 - virtual void print_raw(char* str) = 0; 43.34 - virtual void print(char* format, ...) = 0; 43.35 - // helpers 43.36 - virtual char* string_for_offset(intptr_t value) = 0; 43.37 - virtual char* string_for_constant(unsigned char* pc, intptr_t value, int is_decimal) = 0; 43.38 -};
44.1 --- a/src/share/vm/compiler/oopMap.cpp Thu Apr 10 15:49:16 2008 -0400 44.2 +++ b/src/share/vm/compiler/oopMap.cpp Fri Apr 11 09:56:35 2008 -0400 44.3 @@ -505,8 +505,13 @@ 44.4 #endif // COMPILER2 44.5 } 44.6 44.7 +#endif //PRODUCT 44.8 44.9 -static void print_register_type(OopMapValue::oop_types x, VMReg optional, outputStream* st) { 44.10 +// Printing code is present in product build for -XX:+PrintAssembly. 44.11 + 44.12 +static 44.13 +void print_register_type(OopMapValue::oop_types x, VMReg optional, 44.14 + outputStream* st) { 44.15 switch( x ) { 44.16 case OopMapValue::oop_value: 44.17 st->print("Oop"); 44.18 @@ -544,10 +549,12 @@ 44.19 44.20 void OopMap::print_on(outputStream* st) const { 44.21 OopMapValue omv; 44.22 + st->print("OopMap{"); 44.23 for(OopMapStream oms((OopMap*)this); !oms.is_done(); oms.next()) { 44.24 omv = oms.current(); 44.25 omv.print_on(st); 44.26 } 44.27 + st->print("off=%d}", (int) offset()); 44.28 } 44.29 44.30 44.31 @@ -558,12 +565,12 @@ 44.32 44.33 for( i = 0; i < len; i++) { 44.34 OopMap* m = at(i); 44.35 - st->print_cr("OopMap #%d offset:%p",i,m->offset()); 44.36 + st->print_cr("#%d ",i); 44.37 m->print_on(st); 44.38 - st->print_cr("\n"); 44.39 + st->cr(); 44.40 } 44.41 } 44.42 -#endif // !PRODUCT 44.43 + 44.44 44.45 44.46 //------------------------------DerivedPointerTable---------------------------
45.1 --- a/src/share/vm/compiler/oopMap.hpp Thu Apr 10 15:49:16 2008 -0400 45.2 +++ b/src/share/vm/compiler/oopMap.hpp Fri Apr 11 09:56:35 2008 -0400 45.3 @@ -129,7 +129,7 @@ 45.4 return reg()->reg2stack(); 45.5 } 45.6 45.7 - void print_on(outputStream* st) const PRODUCT_RETURN; 45.8 + void print_on(outputStream* st) const; 45.9 void print() const { print_on(tty); } 45.10 }; 45.11 45.12 @@ -193,7 +193,7 @@ 45.13 } 45.14 45.15 // Printing 45.16 - void print_on(outputStream* st) const PRODUCT_RETURN; 45.17 + void print_on(outputStream* st) const; 45.18 void print() const { print_on(tty); } 45.19 }; 45.20 45.21 @@ -248,7 +248,7 @@ 45.22 OopClosure* value_fn, OopClosure* dead_fn); 45.23 45.24 // Printing 45.25 - void print_on(outputStream* st) const PRODUCT_RETURN; 45.26 + void print_on(outputStream* st) const; 45.27 void print() const { print_on(tty); } 45.28 }; 45.29
46.1 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Thu Apr 10 15:49:16 2008 -0400 46.2 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Fri Apr 11 09:56:35 2008 -0400 46.3 @@ -225,6 +225,34 @@ 46.4 assert(_dilatation_factor >= 1.0, "from previous assert"); 46.5 } 46.6 46.7 + 46.8 +// The field "_initiating_occupancy" represents the occupancy percentage 46.9 +// at which we trigger a new collection cycle. Unless explicitly specified 46.10 +// via CMSInitiating[Perm]OccupancyFraction (argument "io" below), it 46.11 +// is calculated by: 46.12 +// 46.13 +// Let "f" be MinHeapFreeRatio in 46.14 +// 46.15 +// _intiating_occupancy = 100-f + 46.16 +// f * (CMSTrigger[Perm]Ratio/100) 46.17 +// where CMSTrigger[Perm]Ratio is the argument "tr" below. 46.18 +// 46.19 +// That is, if we assume the heap is at its desired maximum occupancy at the 46.20 +// end of a collection, we let CMSTrigger[Perm]Ratio of the (purported) free 46.21 +// space be allocated before initiating a new collection cycle. 46.22 +// 46.23 +void ConcurrentMarkSweepGeneration::init_initiating_occupancy(intx io, intx tr) { 46.24 + assert(io <= 100 && tr >= 0 && tr <= 100, "Check the arguments"); 46.25 + if (io >= 0) { 46.26 + _initiating_occupancy = (double)io / 100.0; 46.27 + } else { 46.28 + _initiating_occupancy = ((100 - MinHeapFreeRatio) + 46.29 + (double)(tr * MinHeapFreeRatio) / 100.0) 46.30 + / 100.0; 46.31 + } 46.32 +} 46.33 + 46.34 + 46.35 void ConcurrentMarkSweepGeneration::ref_processor_init() { 46.36 assert(collector() != NULL, "no collector"); 46.37 collector()->ref_processor_init(); 46.38 @@ -520,8 +548,8 @@ 46.39 _verification_mark_bm(0, Mutex::leaf + 1, "CMS_verification_mark_bm_lock"), 46.40 _completed_initialization(false), 46.41 _collector_policy(cp), 46.42 - _unload_classes(false), 46.43 - _unloaded_classes_last_cycle(false), 46.44 + _should_unload_classes(false), 46.45 + _concurrent_cycles_since_last_unload(0), 46.46 _sweep_estimate(CMS_SweepWeight, CMS_SweepPadding) 46.47 { 46.48 if (ExplicitGCInvokesConcurrentAndUnloadsClasses) { 46.49 @@ -642,26 +670,11 @@ 46.50 } 46.51 } 46.52 46.53 - // "initiatingOccupancy" is the occupancy ratio at which we trigger 46.54 - // a new collection cycle. Unless explicitly specified via 46.55 - // CMSTriggerRatio, it is calculated by: 46.56 - // Let "f" be MinHeapFreeRatio in 46.57 - // 46.58 - // intiatingOccupancy = 100-f + 46.59 - // f * (CMSTriggerRatio/100) 46.60 - // That is, if we assume the heap is at its desired maximum occupancy at the 46.61 - // end of a collection, we let CMSTriggerRatio of the (purported) free 46.62 - // space be allocated before initiating a new collection cycle. 46.63 - if (CMSInitiatingOccupancyFraction > 0) { 46.64 - _initiatingOccupancy = (double)CMSInitiatingOccupancyFraction / 100.0; 46.65 - } else { 46.66 - _initiatingOccupancy = ((100 - MinHeapFreeRatio) + 46.67 - (double)(CMSTriggerRatio * 46.68 - MinHeapFreeRatio) / 100.0) 46.69 - / 100.0; 46.70 - } 46.71 + _cmsGen ->init_initiating_occupancy(CMSInitiatingOccupancyFraction, CMSTriggerRatio); 46.72 + _permGen->init_initiating_occupancy(CMSInitiatingPermOccupancyFraction, CMSTriggerPermRatio); 46.73 + 46.74 // Clip CMSBootstrapOccupancy between 0 and 100. 46.75 - _bootstrap_occupancy = ((double)MIN2((intx)100, MAX2((intx)0, CMSBootstrapOccupancy))) 46.76 + _bootstrap_occupancy = ((double)MIN2((uintx)100, MAX2((uintx)0, CMSBootstrapOccupancy))) 46.77 /(double)100; 46.78 46.79 _full_gcs_since_conc_gc = 0; 46.80 @@ -1413,7 +1426,8 @@ 46.81 gclog_or_tty->print_cr("promotion_rate=%g", stats().promotion_rate()); 46.82 gclog_or_tty->print_cr("cms_allocation_rate=%g", stats().cms_allocation_rate()); 46.83 gclog_or_tty->print_cr("occupancy=%3.7f", _cmsGen->occupancy()); 46.84 - gclog_or_tty->print_cr("initiatingOccupancy=%3.7f", initiatingOccupancy()); 46.85 + gclog_or_tty->print_cr("initiatingOccupancy=%3.7f", _cmsGen->initiating_occupancy()); 46.86 + gclog_or_tty->print_cr("initiatingPermOccupancy=%3.7f", _permGen->initiating_occupancy()); 46.87 } 46.88 // ------------------------------------------------------------------ 46.89 46.90 @@ -1446,84 +1460,91 @@ 46.91 // old gen want a collection cycle started. Each may use 46.92 // an appropriate criterion for making this decision. 46.93 // XXX We need to make sure that the gen expansion 46.94 - // criterion dovetails well with this. 46.95 - if (_cmsGen->shouldConcurrentCollect(initiatingOccupancy())) { 46.96 + // criterion dovetails well with this. XXX NEED TO FIX THIS 46.97 + if (_cmsGen->should_concurrent_collect()) { 46.98 if (Verbose && PrintGCDetails) { 46.99 gclog_or_tty->print_cr("CMS old gen initiated"); 46.100 } 46.101 return true; 46.102 } 46.103 46.104 - if (cms_should_unload_classes() && 46.105 - _permGen->shouldConcurrentCollect(initiatingOccupancy())) { 46.106 - if (Verbose && PrintGCDetails) { 46.107 - gclog_or_tty->print_cr("CMS perm gen initiated"); 46.108 - } 46.109 - return true; 46.110 - } 46.111 - 46.112 - return false; 46.113 -} 46.114 - 46.115 -// Clear _expansion_cause fields of constituent generations 46.116 -void CMSCollector::clear_expansion_cause() { 46.117 - _cmsGen->clear_expansion_cause(); 46.118 - _permGen->clear_expansion_cause(); 46.119 -} 46.120 - 46.121 -bool ConcurrentMarkSweepGeneration::shouldConcurrentCollect( 46.122 - double initiatingOccupancy) { 46.123 - // We should be conservative in starting a collection cycle. To 46.124 - // start too eagerly runs the risk of collecting too often in the 46.125 - // extreme. To collect too rarely falls back on full collections, 46.126 - // which works, even if not optimum in terms of concurrent work. 46.127 - // As a work around for too eagerly collecting, use the flag 46.128 - // UseCMSInitiatingOccupancyOnly. This also has the advantage of 46.129 - // giving the user an easily understandable way of controlling the 46.130 - // collections. 46.131 - // We want to start a new collection cycle if any of the following 46.132 - // conditions hold: 46.133 - // . our current occupancy exceeds the initiating occupancy, or 46.134 - // . we recently needed to expand and have not since that expansion, 46.135 - // collected, or 46.136 - // . we are not using adaptive free lists and linear allocation is 46.137 - // going to fail, or 46.138 - // . (for old gen) incremental collection has already failed or 46.139 - // may soon fail in the near future as we may not be able to absorb 46.140 - // promotions. 46.141 - assert_lock_strong(freelistLock()); 46.142 - 46.143 - if (occupancy() > initiatingOccupancy) { 46.144 - if (PrintGCDetails && Verbose) { 46.145 - gclog_or_tty->print(" %s: collect because of occupancy %f / %f ", 46.146 - short_name(), occupancy(), initiatingOccupancy); 46.147 - } 46.148 - return true; 46.149 - } 46.150 - if (UseCMSInitiatingOccupancyOnly) { 46.151 - return false; 46.152 - } 46.153 - if (expansion_cause() == CMSExpansionCause::_satisfy_allocation) { 46.154 - if (PrintGCDetails && Verbose) { 46.155 - gclog_or_tty->print(" %s: collect because expanded for allocation ", 46.156 - short_name()); 46.157 - } 46.158 - return true; 46.159 - } 46.160 + // We start a collection if we believe an incremental collection may fail; 46.161 + // this is not likely to be productive in practice because it's probably too 46.162 + // late anyway. 46.163 GenCollectedHeap* gch = GenCollectedHeap::heap(); 46.164 assert(gch->collector_policy()->is_two_generation_policy(), 46.165 "You may want to check the correctness of the following"); 46.166 if (gch->incremental_collection_will_fail()) { 46.167 if (PrintGCDetails && Verbose) { 46.168 - gclog_or_tty->print(" %s: collect because incremental collection will fail ", 46.169 + gclog_or_tty->print("CMSCollector: collect because incremental collection will fail "); 46.170 + } 46.171 + return true; 46.172 + } 46.173 + 46.174 + if (CMSClassUnloadingEnabled && _permGen->should_concurrent_collect()) { 46.175 + bool res = update_should_unload_classes(); 46.176 + if (res) { 46.177 + if (Verbose && PrintGCDetails) { 46.178 + gclog_or_tty->print_cr("CMS perm gen initiated"); 46.179 + } 46.180 + return true; 46.181 + } 46.182 + } 46.183 + return false; 46.184 +} 46.185 + 46.186 +// Clear _expansion_cause fields of constituent generations 46.187 +void CMSCollector::clear_expansion_cause() { 46.188 + _cmsGen->clear_expansion_cause(); 46.189 + _permGen->clear_expansion_cause(); 46.190 +} 46.191 + 46.192 +// We should be conservative in starting a collection cycle. To 46.193 +// start too eagerly runs the risk of collecting too often in the 46.194 +// extreme. To collect too rarely falls back on full collections, 46.195 +// which works, even if not optimum in terms of concurrent work. 46.196 +// As a work around for too eagerly collecting, use the flag 46.197 +// UseCMSInitiatingOccupancyOnly. This also has the advantage of 46.198 +// giving the user an easily understandable way of controlling the 46.199 +// collections. 46.200 +// We want to start a new collection cycle if any of the following 46.201 +// conditions hold: 46.202 +// . our current occupancy exceeds the configured initiating occupancy 46.203 +// for this generation, or 46.204 +// . we recently needed to expand this space and have not, since that 46.205 +// expansion, done a collection of this generation, or 46.206 +// . the underlying space believes that it may be a good idea to initiate 46.207 +// a concurrent collection (this may be based on criteria such as the 46.208 +// following: the space uses linear allocation and linear allocation is 46.209 +// going to fail, or there is believed to be excessive fragmentation in 46.210 +// the generation, etc... or ... 46.211 +// [.(currently done by CMSCollector::shouldConcurrentCollect() only for 46.212 +// the case of the old generation, not the perm generation; see CR 6543076): 46.213 +// we may be approaching a point at which allocation requests may fail because 46.214 +// we will be out of sufficient free space given allocation rate estimates.] 46.215 +bool ConcurrentMarkSweepGeneration::should_concurrent_collect() const { 46.216 + 46.217 + assert_lock_strong(freelistLock()); 46.218 + if (occupancy() > initiating_occupancy()) { 46.219 + if (PrintGCDetails && Verbose) { 46.220 + gclog_or_tty->print(" %s: collect because of occupancy %f / %f ", 46.221 + short_name(), occupancy(), initiating_occupancy()); 46.222 + } 46.223 + return true; 46.224 + } 46.225 + if (UseCMSInitiatingOccupancyOnly) { 46.226 + return false; 46.227 + } 46.228 + if (expansion_cause() == CMSExpansionCause::_satisfy_allocation) { 46.229 + if (PrintGCDetails && Verbose) { 46.230 + gclog_or_tty->print(" %s: collect because expanded for allocation ", 46.231 short_name()); 46.232 } 46.233 return true; 46.234 } 46.235 - if (!_cmsSpace->adaptive_freelists() && 46.236 - _cmsSpace->linearAllocationWouldFail()) { 46.237 + if (_cmsSpace->should_concurrent_collect()) { 46.238 if (PrintGCDetails && Verbose) { 46.239 - gclog_or_tty->print(" %s: collect because of linAB ", 46.240 + gclog_or_tty->print(" %s: collect because cmsSpace says so ", 46.241 short_name()); 46.242 } 46.243 return true; 46.244 @@ -1970,8 +1991,9 @@ 46.245 "Should have been NULL'd before baton was passed"); 46.246 reset(false /* == !asynch */); 46.247 _cmsGen->reset_after_compaction(); 46.248 - 46.249 - if (verifying() && !cms_should_unload_classes()) { 46.250 + _concurrent_cycles_since_last_unload = 0; 46.251 + 46.252 + if (verifying() && !should_unload_classes()) { 46.253 perm_gen_verify_bit_map()->clear_all(); 46.254 } 46.255 46.256 @@ -2098,6 +2120,7 @@ 46.257 { 46.258 bool safepoint_check = Mutex::_no_safepoint_check_flag; 46.259 MutexLockerEx hl(Heap_lock, safepoint_check); 46.260 + FreelistLocker fll(this); 46.261 MutexLockerEx x(CGC_lock, safepoint_check); 46.262 if (_foregroundGCIsActive || !UseAsyncConcMarkSweepGC) { 46.263 // The foreground collector is active or we're 46.264 @@ -2112,13 +2135,9 @@ 46.265 // a new cycle. 46.266 clear_expansion_cause(); 46.267 } 46.268 - _unloaded_classes_last_cycle = cms_should_unload_classes(); // ... from last cycle 46.269 - // This controls class unloading in response to an explicit gc request. 46.270 - // If ExplicitGCInvokesConcurrentAndUnloadsClasses is set, then 46.271 - // we will unload classes even if CMSClassUnloadingEnabled is not set. 46.272 - // See CR 6541037 and related CRs. 46.273 - _unload_classes = _full_gc_requested // ... for this cycle 46.274 - && ExplicitGCInvokesConcurrentAndUnloadsClasses; 46.275 + // Decide if we want to enable class unloading as part of the 46.276 + // ensuing concurrent GC cycle. 46.277 + update_should_unload_classes(); 46.278 _full_gc_requested = false; // acks all outstanding full gc requests 46.279 // Signal that we are about to start a collection 46.280 gch->increment_total_full_collections(); // ... starting a collection cycle 46.281 @@ -3047,21 +3066,62 @@ 46.282 } 46.283 #endif // PRODUCT 46.284 46.285 +// Decide if we want to enable class unloading as part of the 46.286 +// ensuing concurrent GC cycle. We will collect the perm gen and 46.287 +// unload classes if it's the case that: 46.288 +// (1) an explicit gc request has been made and the flag 46.289 +// ExplicitGCInvokesConcurrentAndUnloadsClasses is set, OR 46.290 +// (2) (a) class unloading is enabled at the command line, and 46.291 +// (b) (i) perm gen threshold has been crossed, or 46.292 +// (ii) old gen is getting really full, or 46.293 +// (iii) the previous N CMS collections did not collect the 46.294 +// perm gen 46.295 +// NOTE: Provided there is no change in the state of the heap between 46.296 +// calls to this method, it should have idempotent results. Moreover, 46.297 +// its results should be monotonically increasing (i.e. going from 0 to 1, 46.298 +// but not 1 to 0) between successive calls between which the heap was 46.299 +// not collected. For the implementation below, it must thus rely on 46.300 +// the property that concurrent_cycles_since_last_unload() 46.301 +// will not decrease unless a collection cycle happened and that 46.302 +// _permGen->should_concurrent_collect() and _cmsGen->is_too_full() are 46.303 +// themselves also monotonic in that sense. See check_monotonicity() 46.304 +// below. 46.305 +bool CMSCollector::update_should_unload_classes() { 46.306 + _should_unload_classes = false; 46.307 + // Condition 1 above 46.308 + if (_full_gc_requested && ExplicitGCInvokesConcurrentAndUnloadsClasses) { 46.309 + _should_unload_classes = true; 46.310 + } else if (CMSClassUnloadingEnabled) { // Condition 2.a above 46.311 + // Disjuncts 2.b.(i,ii,iii) above 46.312 + _should_unload_classes = (concurrent_cycles_since_last_unload() >= 46.313 + CMSClassUnloadingMaxInterval) 46.314 + || _permGen->should_concurrent_collect() 46.315 + || _cmsGen->is_too_full(); 46.316 + } 46.317 + return _should_unload_classes; 46.318 +} 46.319 + 46.320 +bool ConcurrentMarkSweepGeneration::is_too_full() const { 46.321 + bool res = should_concurrent_collect(); 46.322 + res = res && (occupancy() > (double)CMSIsTooFullPercentage/100.0); 46.323 + return res; 46.324 +} 46.325 + 46.326 void CMSCollector::setup_cms_unloading_and_verification_state() { 46.327 const bool should_verify = VerifyBeforeGC || VerifyAfterGC || VerifyDuringGC 46.328 || VerifyBeforeExit; 46.329 const int rso = SharedHeap::SO_Symbols | SharedHeap::SO_Strings 46.330 | SharedHeap::SO_CodeCache; 46.331 46.332 - if (cms_should_unload_classes()) { // Should unload classes this cycle 46.333 + if (should_unload_classes()) { // Should unload classes this cycle 46.334 remove_root_scanning_option(rso); // Shrink the root set appropriately 46.335 set_verifying(should_verify); // Set verification state for this cycle 46.336 return; // Nothing else needs to be done at this time 46.337 } 46.338 46.339 // Not unloading classes this cycle 46.340 - assert(!cms_should_unload_classes(), "Inconsitency!"); 46.341 - if ((!verifying() || cms_unloaded_classes_last_cycle()) && should_verify) { 46.342 + assert(!should_unload_classes(), "Inconsitency!"); 46.343 + if ((!verifying() || unloaded_classes_last_cycle()) && should_verify) { 46.344 // We were not verifying, or we _were_ unloading classes in the last cycle, 46.345 // AND some verification options are enabled this cycle; in this case, 46.346 // we must make sure that the deadness map is allocated if not already so, 46.347 @@ -4693,7 +4753,7 @@ 46.348 46.349 GenCollectedHeap* gch = GenCollectedHeap::heap(); 46.350 46.351 - if (cms_should_unload_classes()) { 46.352 + if (should_unload_classes()) { 46.353 CodeCache::gc_prologue(); 46.354 } 46.355 assert(haveFreelistLocks(), "must have free list locks"); 46.356 @@ -4753,7 +4813,7 @@ 46.357 verify_work_stacks_empty(); 46.358 verify_overflow_empty(); 46.359 46.360 - if (cms_should_unload_classes()) { 46.361 + if (should_unload_classes()) { 46.362 CodeCache::gc_epilogue(); 46.363 } 46.364 46.365 @@ -5623,7 +5683,7 @@ 46.366 verify_work_stacks_empty(); 46.367 } 46.368 46.369 - if (cms_should_unload_classes()) { 46.370 + if (should_unload_classes()) { 46.371 { 46.372 TraceTime t("class unloading", PrintGCDetails, false, gclog_or_tty); 46.373 46.374 @@ -5726,7 +5786,7 @@ 46.375 // this cycle, we preserve the perm gen object "deadness" information 46.376 // in the perm_gen_verify_bit_map. In order to do that we traverse 46.377 // all blocks in perm gen and mark all dead objects. 46.378 - if (verifying() && !cms_should_unload_classes()) { 46.379 + if (verifying() && !should_unload_classes()) { 46.380 assert(perm_gen_verify_bit_map()->sizeInBits() != 0, 46.381 "Should have already been allocated"); 46.382 MarkDeadObjectsClosure mdo(this, _permGen->cmsSpace(), 46.383 @@ -5753,7 +5813,7 @@ 46.384 } 46.385 46.386 // Now repeat for perm gen 46.387 - if (cms_should_unload_classes()) { 46.388 + if (should_unload_classes()) { 46.389 CMSTokenSyncWithLocks ts(true, _permGen->freelistLock(), 46.390 bitMapLock()); 46.391 sweepWork(_permGen, asynch); 46.392 @@ -5775,7 +5835,7 @@ 46.393 // already have needed locks 46.394 sweepWork(_cmsGen, asynch); 46.395 46.396 - if (cms_should_unload_classes()) { 46.397 + if (should_unload_classes()) { 46.398 sweepWork(_permGen, asynch); 46.399 } 46.400 // Update heap occupancy information which is used as 46.401 @@ -5937,6 +5997,11 @@ 46.402 } 46.403 gen->cmsSpace()->sweep_completed(); 46.404 gen->cmsSpace()->endSweepFLCensus(sweepCount()); 46.405 + if (should_unload_classes()) { // unloaded classes this cycle, 46.406 + _concurrent_cycles_since_last_unload = 0; // ... reset count 46.407 + } else { // did not unload classes, 46.408 + _concurrent_cycles_since_last_unload++; // ... increment count 46.409 + } 46.410 } 46.411 46.412 // Reset CMS data structures (for now just the marking bit map) 46.413 @@ -7194,7 +7259,7 @@ 46.414 _revisitStack(revisitStack), 46.415 _finger(finger), 46.416 _parent(parent), 46.417 - _should_remember_klasses(collector->cms_should_unload_classes()) 46.418 + _should_remember_klasses(collector->should_unload_classes()) 46.419 { } 46.420 46.421 Par_PushOrMarkClosure::Par_PushOrMarkClosure(CMSCollector* collector, 46.422 @@ -7217,7 +7282,7 @@ 46.423 _finger(finger), 46.424 _global_finger_addr(global_finger_addr), 46.425 _parent(parent), 46.426 - _should_remember_klasses(collector->cms_should_unload_classes()) 46.427 + _should_remember_klasses(collector->should_unload_classes()) 46.428 { } 46.429 46.430 46.431 @@ -7360,7 +7425,7 @@ 46.432 _mark_stack(mark_stack), 46.433 _revisit_stack(revisit_stack), 46.434 _concurrent_precleaning(concurrent_precleaning), 46.435 - _should_remember_klasses(collector->cms_should_unload_classes()) 46.436 + _should_remember_klasses(collector->should_unload_classes()) 46.437 { 46.438 assert(_ref_processor != NULL, "_ref_processor shouldn't be NULL"); 46.439 } 46.440 @@ -7422,7 +7487,7 @@ 46.441 _bit_map(bit_map), 46.442 _work_queue(work_queue), 46.443 _revisit_stack(revisit_stack), 46.444 - _should_remember_klasses(collector->cms_should_unload_classes()) 46.445 + _should_remember_klasses(collector->should_unload_classes()) 46.446 { 46.447 assert(_ref_processor != NULL, "_ref_processor shouldn't be NULL"); 46.448 } 46.449 @@ -7944,7 +8009,7 @@ 46.450 46.451 #ifdef DEBUG 46.452 if (oop(addr)->klass() != NULL && 46.453 - ( !_collector->cms_should_unload_classes() 46.454 + ( !_collector->should_unload_classes() 46.455 || oop(addr)->is_parsable())) { 46.456 // Ignore mark word because we are running concurrent with mutators 46.457 assert(oop(addr)->is_oop(true), "live block should be an oop"); 46.458 @@ -7957,7 +8022,7 @@ 46.459 } else { 46.460 // This should be an initialized object that's alive. 46.461 assert(oop(addr)->klass() != NULL && 46.462 - (!_collector->cms_should_unload_classes() 46.463 + (!_collector->should_unload_classes() 46.464 || oop(addr)->is_parsable()), 46.465 "Should be an initialized object"); 46.466 // Ignore mark word because we are running concurrent with mutators
47.1 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Thu Apr 10 15:49:16 2008 -0400 47.2 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Fri Apr 11 09:56:35 2008 -0400 47.3 @@ -535,13 +535,16 @@ 47.4 // In support of ExplicitGCInvokesConcurrent 47.5 static bool _full_gc_requested; 47.6 unsigned int _collection_count_start; 47.7 + 47.8 // Should we unload classes this concurrent cycle? 47.9 - // Set in response to a concurrent full gc request. 47.10 - bool _unload_classes; 47.11 - bool _unloaded_classes_last_cycle; 47.12 + bool _should_unload_classes; 47.13 + unsigned int _concurrent_cycles_since_last_unload; 47.14 + unsigned int concurrent_cycles_since_last_unload() const { 47.15 + return _concurrent_cycles_since_last_unload; 47.16 + } 47.17 // Did we (allow) unload classes in the previous concurrent cycle? 47.18 - bool cms_unloaded_classes_last_cycle() const { 47.19 - return _unloaded_classes_last_cycle || CMSClassUnloadingEnabled; 47.20 + bool unloaded_classes_last_cycle() const { 47.21 + return concurrent_cycles_since_last_unload() == 0; 47.22 } 47.23 47.24 // Verification support 47.25 @@ -651,8 +654,6 @@ 47.26 // number of full gc's since the last concurrent gc. 47.27 uint _full_gcs_since_conc_gc; 47.28 47.29 - // if occupancy exceeds this, start a new gc cycle 47.30 - double _initiatingOccupancy; 47.31 // occupancy used for bootstrapping stats 47.32 double _bootstrap_occupancy; 47.33 47.34 @@ -825,7 +826,6 @@ 47.35 47.36 Mutex* bitMapLock() const { return _markBitMap.lock(); } 47.37 static CollectorState abstract_state() { return _collectorState; } 47.38 - double initiatingOccupancy() const { return _initiatingOccupancy; } 47.39 47.40 bool should_abort_preclean() const; // Whether preclean should be aborted. 47.41 size_t get_eden_used() const; 47.42 @@ -849,11 +849,10 @@ 47.43 // In support of ExplicitGCInvokesConcurrent 47.44 static void request_full_gc(unsigned int full_gc_count); 47.45 // Should we unload classes in a particular concurrent cycle? 47.46 - bool cms_should_unload_classes() const { 47.47 - assert(!_unload_classes || ExplicitGCInvokesConcurrentAndUnloadsClasses, 47.48 - "Inconsistency; see CR 6541037"); 47.49 - return _unload_classes || CMSClassUnloadingEnabled; 47.50 + bool should_unload_classes() const { 47.51 + return _should_unload_classes; 47.52 } 47.53 + bool update_should_unload_classes(); 47.54 47.55 void direct_allocated(HeapWord* start, size_t size); 47.56 47.57 @@ -1022,6 +1021,10 @@ 47.58 _incremental_collection_failed = false; 47.59 } 47.60 47.61 + // accessors 47.62 + void set_expansion_cause(CMSExpansionCause::Cause v) { _expansion_cause = v;} 47.63 + CMSExpansionCause::Cause expansion_cause() const { return _expansion_cause; } 47.64 + 47.65 private: 47.66 // For parallel young-gen GC support. 47.67 CMSParGCThreadState** _par_gc_thread_states; 47.68 @@ -1029,10 +1032,6 @@ 47.69 // Reason generation was expanded 47.70 CMSExpansionCause::Cause _expansion_cause; 47.71 47.72 - // accessors 47.73 - void set_expansion_cause(CMSExpansionCause::Cause v) { _expansion_cause = v;} 47.74 - CMSExpansionCause::Cause expansion_cause() { return _expansion_cause; } 47.75 - 47.76 // In support of MinChunkSize being larger than min object size 47.77 const double _dilatation_factor; 47.78 47.79 @@ -1045,6 +1044,10 @@ 47.80 47.81 CollectionTypes _debug_collection_type; 47.82 47.83 + // Fraction of current occupancy at which to start a CMS collection which 47.84 + // will collect this generation (at least). 47.85 + double _initiating_occupancy; 47.86 + 47.87 protected: 47.88 // Grow generation by specified size (returns false if unable to grow) 47.89 bool grow_by(size_t bytes); 47.90 @@ -1060,6 +1063,10 @@ 47.91 // space. 47.92 size_t max_available() const; 47.93 47.94 + // getter and initializer for _initiating_occupancy field. 47.95 + double initiating_occupancy() const { return _initiating_occupancy; } 47.96 + void init_initiating_occupancy(intx io, intx tr); 47.97 + 47.98 public: 47.99 ConcurrentMarkSweepGeneration(ReservedSpace rs, size_t initial_byte_size, 47.100 int level, CardTableRS* ct, 47.101 @@ -1103,7 +1110,7 @@ 47.102 size_t capacity() const; 47.103 size_t used() const; 47.104 size_t free() const; 47.105 - double occupancy() { return ((double)used())/((double)capacity()); } 47.106 + double occupancy() const { return ((double)used())/((double)capacity()); } 47.107 size_t contiguous_available() const; 47.108 size_t unsafe_max_alloc_nogc() const; 47.109 47.110 @@ -1158,8 +1165,8 @@ 47.111 bool younger_handles_promotion_failure) const; 47.112 47.113 bool should_collect(bool full, size_t size, bool tlab); 47.114 - // XXXPERM 47.115 - bool shouldConcurrentCollect(double initiatingOccupancy); // XXXPERM 47.116 + virtual bool should_concurrent_collect() const; 47.117 + virtual bool is_too_full() const; 47.118 void collect(bool full, 47.119 bool clear_all_soft_refs, 47.120 size_t size,
48.1 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.inline.hpp Thu Apr 10 15:49:16 2008 -0400 48.2 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.inline.hpp Fri Apr 11 09:56:35 2008 -0400 48.3 @@ -267,7 +267,7 @@ 48.4 (_permGen->cmsSpace()->is_in_reserved(addr) 48.5 && _permGen->cmsSpace()->block_is_obj(addr)), 48.6 "must be object"); 48.7 - return cms_should_unload_classes() && 48.8 + return should_unload_classes() && 48.9 _collectorState == Sweeping && 48.10 !_markBitMap.isMarked(addr); 48.11 }
49.1 --- a/src/share/vm/includeDB_compiler1 Thu Apr 10 15:49:16 2008 -0400 49.2 +++ b/src/share/vm/includeDB_compiler1 Fri Apr 11 09:56:35 2008 -0400 49.3 @@ -323,7 +323,7 @@ 49.4 c1_Runtime1.cpp compilationPolicy.hpp 49.5 c1_Runtime1.cpp compiledIC.hpp 49.6 c1_Runtime1.cpp copy.hpp 49.7 -c1_Runtime1.cpp disassembler_<arch>.hpp 49.8 +c1_Runtime1.cpp disassembler.hpp 49.9 c1_Runtime1.cpp events.hpp 49.10 c1_Runtime1.cpp interfaceSupport.hpp 49.11 c1_Runtime1.cpp interpreter.hpp
50.1 --- a/src/share/vm/includeDB_core Thu Apr 10 15:49:16 2008 -0400 50.2 +++ b/src/share/vm/includeDB_core Fri Apr 11 09:56:35 2008 -0400 50.3 @@ -244,7 +244,7 @@ 50.4 50.5 assembler.inline.hpp assembler.hpp 50.6 assembler.inline.hpp codeBuffer.hpp 50.7 -assembler.inline.hpp disassembler_<arch>.hpp 50.8 +assembler.inline.hpp disassembler.hpp 50.9 assembler.inline.hpp threadLocalStorage.hpp 50.10 50.11 assembler_<arch_model>.cpp assembler_<arch_model>.inline.hpp 50.12 @@ -946,7 +946,7 @@ 50.13 codeBlob.cpp bytecode.hpp 50.14 codeBlob.cpp codeBlob.hpp 50.15 codeBlob.cpp codeCache.hpp 50.16 -codeBlob.cpp disassembler_<arch>.hpp 50.17 +codeBlob.cpp disassembler.hpp 50.18 codeBlob.cpp forte.hpp 50.19 codeBlob.cpp handles.inline.hpp 50.20 codeBlob.cpp heap.hpp 50.21 @@ -968,7 +968,7 @@ 50.22 50.23 codeBuffer.cpp codeBuffer.hpp 50.24 codeBuffer.cpp copy.hpp 50.25 -codeBuffer.cpp disassembler_<arch>.hpp 50.26 +codeBuffer.cpp disassembler.hpp 50.27 50.28 codeBuffer.hpp assembler.hpp 50.29 codeBuffer.hpp oopRecorder.hpp 50.30 @@ -1323,7 +1323,7 @@ 50.31 debug.cpp collectedHeap.hpp 50.32 debug.cpp compileBroker.hpp 50.33 debug.cpp defaultStream.hpp 50.34 -debug.cpp disassembler_<arch>.hpp 50.35 +debug.cpp disassembler.hpp 50.36 debug.cpp events.hpp 50.37 debug.cpp frame.hpp 50.38 debug.cpp heapDumper.hpp 50.39 @@ -1442,7 +1442,7 @@ 50.40 deoptimization.hpp frame.inline.hpp 50.41 50.42 depChecker_<arch>.cpp depChecker_<arch>.hpp 50.43 -depChecker_<arch>.cpp disassembler_<arch>.hpp 50.44 +depChecker_<arch>.cpp disassembler.hpp 50.45 depChecker_<arch>.cpp hpi.hpp 50.46 50.47 dependencies.cpp ciArrayKlass.hpp 50.48 @@ -1472,21 +1472,21 @@ 50.49 dictionary.hpp oop.hpp 50.50 dictionary.hpp systemDictionary.hpp 50.51 50.52 -disassemblerEnv.hpp globals.hpp 50.53 - 50.54 -disassembler_<arch>.cpp cardTableModRefBS.hpp 50.55 -disassembler_<arch>.cpp codeCache.hpp 50.56 -disassembler_<arch>.cpp collectedHeap.hpp 50.57 -disassembler_<arch>.cpp depChecker_<arch>.hpp 50.58 -disassembler_<arch>.cpp disassembler_<arch>.hpp 50.59 -disassembler_<arch>.cpp fprofiler.hpp 50.60 -disassembler_<arch>.cpp handles.inline.hpp 50.61 -disassembler_<arch>.cpp hpi.hpp 50.62 -disassembler_<arch>.cpp stubCodeGenerator.hpp 50.63 -disassembler_<arch>.cpp stubRoutines.hpp 50.64 - 50.65 -disassembler_<arch>.hpp disassemblerEnv.hpp 50.66 -disassembler_<arch>.hpp os_<os_family>.inline.hpp 50.67 +disassembler_<arch>.hpp generate_platform_dependent_include 50.68 + 50.69 +disassembler.cpp cardTableModRefBS.hpp 50.70 +disassembler.cpp codeCache.hpp 50.71 +disassembler.cpp collectedHeap.hpp 50.72 +disassembler.cpp depChecker_<arch>.hpp 50.73 +disassembler.cpp disassembler.hpp 50.74 +disassembler.cpp fprofiler.hpp 50.75 +disassembler.cpp handles.inline.hpp 50.76 +disassembler.cpp hpi.hpp 50.77 +disassembler.cpp stubCodeGenerator.hpp 50.78 +disassembler.cpp stubRoutines.hpp 50.79 + 50.80 +disassembler.hpp globals.hpp 50.81 +disassembler.hpp os_<os_family>.inline.hpp 50.82 50.83 dtraceAttacher.cpp codeCache.hpp 50.84 dtraceAttacher.cpp deoptimization.hpp 50.85 @@ -2909,7 +2909,7 @@ 50.86 nmethod.cpp compileLog.hpp 50.87 nmethod.cpp compiledIC.hpp 50.88 nmethod.cpp compilerOracle.hpp 50.89 -nmethod.cpp disassembler_<arch>.hpp 50.90 +nmethod.cpp disassembler.hpp 50.91 nmethod.cpp dtrace.hpp 50.92 nmethod.cpp events.hpp 50.93 nmethod.cpp jvmtiRedefineClassesTrace.hpp 50.94 @@ -3763,7 +3763,7 @@ 50.95 statSampler.hpp task.hpp 50.96 50.97 stubCodeGenerator.cpp assembler_<arch_model>.inline.hpp 50.98 -stubCodeGenerator.cpp disassembler_<arch>.hpp 50.99 +stubCodeGenerator.cpp disassembler.hpp 50.100 stubCodeGenerator.cpp forte.hpp 50.101 stubCodeGenerator.cpp oop.inline.hpp 50.102 stubCodeGenerator.cpp stubCodeGenerator.hpp 50.103 @@ -4530,7 +4530,7 @@ 50.104 vmreg_<arch>.hpp generate_platform_dependent_include 50.105 50.106 vtableStubs.cpp allocation.inline.hpp 50.107 -vtableStubs.cpp disassembler_<arch>.hpp 50.108 +vtableStubs.cpp disassembler.hpp 50.109 vtableStubs.cpp forte.hpp 50.110 vtableStubs.cpp handles.inline.hpp 50.111 vtableStubs.cpp instanceKlass.hpp
51.1 --- a/src/share/vm/memory/gcLocker.hpp Thu Apr 10 15:49:16 2008 -0400 51.2 +++ b/src/share/vm/memory/gcLocker.hpp Fri Apr 11 09:56:35 2008 -0400 51.3 @@ -184,7 +184,9 @@ 51.4 Thread *_thread; 51.5 public: 51.6 #ifdef ASSERT 51.7 - No_Safepoint_Verifier(bool activated = true, bool verifygc = true ) : No_GC_Verifier(verifygc) { 51.8 + No_Safepoint_Verifier(bool activated = true, bool verifygc = true ) : 51.9 + No_GC_Verifier(verifygc), 51.10 + _activated(activated) { 51.11 _thread = Thread::current(); 51.12 if (_activated) { 51.13 _thread->_allow_allocation_count++;
52.1 --- a/src/share/vm/oops/methodOop.cpp Thu Apr 10 15:49:16 2008 -0400 52.2 +++ b/src/share/vm/oops/methodOop.cpp Fri Apr 11 09:56:35 2008 -0400 52.3 @@ -888,10 +888,11 @@ 52.4 symbolHandle name (THREAD, sym); 52.5 klassOop klass = SystemDictionary::resolve_or_null(name, class_loader, 52.6 protection_domain, THREAD); 52.7 - // We are loading classes eagerly. If a ClassNotFoundException was generated, 52.8 - // be sure to ignore it. 52.9 + // We are loading classes eagerly. If a ClassNotFoundException or 52.10 + // a LinkageError was generated, be sure to ignore it. 52.11 if (HAS_PENDING_EXCEPTION) { 52.12 - if (PENDING_EXCEPTION->is_a(SystemDictionary::classNotFoundException_klass())) { 52.13 + if (PENDING_EXCEPTION->is_a(SystemDictionary::classNotFoundException_klass()) || 52.14 + PENDING_EXCEPTION->is_a(SystemDictionary::linkageError_klass())) { 52.15 CLEAR_PENDING_EXCEPTION; 52.16 } else { 52.17 return false;
53.1 --- a/src/share/vm/opto/addnode.cpp Thu Apr 10 15:49:16 2008 -0400 53.2 +++ b/src/share/vm/opto/addnode.cpp Fri Apr 11 09:56:35 2008 -0400 53.3 @@ -70,9 +70,14 @@ 53.4 53.5 // Convert "Load+x" into "x+Load". 53.6 // Now check for loads 53.7 - if( in2->is_Load() ) return false; 53.8 - // Left is a Load and Right is not; move it right. 53.9 - if( in1->is_Load() ) { 53.10 + if (in2->is_Load()) { 53.11 + if (!in1->is_Load()) { 53.12 + // already x+Load to return 53.13 + return false; 53.14 + } 53.15 + // both are loads, so fall through to sort inputs by idx 53.16 + } else if( in1->is_Load() ) { 53.17 + // Left is a Load and Right is not; move it right. 53.18 add->swap_edges(1, 2); 53.19 return true; 53.20 }
54.1 --- a/src/share/vm/opto/compile.cpp Thu Apr 10 15:49:16 2008 -0400 54.2 +++ b/src/share/vm/opto/compile.cpp Fri Apr 11 09:56:35 2008 -0400 54.3 @@ -456,7 +456,15 @@ 54.4 } 54.5 TraceTime t1("Total compilation time", &_t_totalCompilation, TimeCompiler, TimeCompiler2); 54.6 TraceTime t2(NULL, &_t_methodCompilation, TimeCompiler, false); 54.7 - set_print_assembly(PrintOptoAssembly || _method->should_print_assembly()); 54.8 + bool print_opto_assembly = PrintOptoAssembly || _method->has_option("PrintOptoAssembly"); 54.9 + if (!print_opto_assembly) { 54.10 + bool print_assembly = (PrintAssembly || _method->should_print_assembly()); 54.11 + if (print_assembly && !Disassembler::can_decode()) { 54.12 + tty->print_cr("PrintAssembly request changed to PrintOptoAssembly"); 54.13 + print_opto_assembly = true; 54.14 + } 54.15 + } 54.16 + set_print_assembly(print_opto_assembly); 54.17 #endif 54.18 54.19 if (ProfileTraps) {
55.1 --- a/src/share/vm/opto/escape.cpp Thu Apr 10 15:49:16 2008 -0400 55.2 +++ b/src/share/vm/opto/escape.cpp Fri Apr 11 09:56:35 2008 -0400 55.3 @@ -256,39 +256,49 @@ 55.4 } 55.5 } 55.6 55.7 -void ConnectionGraph::remove_deferred(uint ni) { 55.8 - VectorSet visited(Thread::current()->resource_area()); 55.9 +void ConnectionGraph::remove_deferred(uint ni, GrowableArray<uint>* deferred_edges, VectorSet* visited) { 55.10 + // This method is most expensive during ConnectionGraph construction. 55.11 + // Reuse vectorSet and an additional growable array for deferred edges. 55.12 + deferred_edges->clear(); 55.13 + visited->Clear(); 55.14 55.15 uint i = 0; 55.16 PointsToNode *ptn = ptnode_adr(ni); 55.17 55.18 - while(i < ptn->edge_count()) { 55.19 + // Mark current edges as visited and move deferred edges to separate array. 55.20 + for (; i < ptn->edge_count(); i++) { 55.21 uint t = ptn->edge_target(i); 55.22 +#ifdef ASSERT 55.23 + assert(!visited->test_set(t), "expecting no duplications"); 55.24 +#else 55.25 + visited->set(t); 55.26 +#endif 55.27 + if (ptn->edge_type(i) == PointsToNode::DeferredEdge) { 55.28 + ptn->remove_edge(t, PointsToNode::DeferredEdge); 55.29 + deferred_edges->append(t); 55.30 + } 55.31 + } 55.32 + for (int next = 0; next < deferred_edges->length(); ++next) { 55.33 + uint t = deferred_edges->at(next); 55.34 PointsToNode *ptt = ptnode_adr(t); 55.35 - if (ptn->edge_type(i) != PointsToNode::DeferredEdge) { 55.36 - i++; 55.37 - } else { 55.38 - ptn->remove_edge(t, PointsToNode::DeferredEdge); 55.39 - if(!visited.test_set(t)) { 55.40 - for (uint j = 0; j < ptt->edge_count(); j++) { 55.41 - uint n1 = ptt->edge_target(j); 55.42 - PointsToNode *pt1 = ptnode_adr(n1); 55.43 - switch(ptt->edge_type(j)) { 55.44 - case PointsToNode::PointsToEdge: 55.45 - add_pointsto_edge(ni, n1); 55.46 - if(n1 == _phantom_object) { 55.47 - // Special case - field set outside (globally escaping). 55.48 - ptn->set_escape_state(PointsToNode::GlobalEscape); 55.49 - } 55.50 - break; 55.51 - case PointsToNode::DeferredEdge: 55.52 - add_deferred_edge(ni, n1); 55.53 - break; 55.54 - case PointsToNode::FieldEdge: 55.55 - assert(false, "invalid connection graph"); 55.56 - break; 55.57 + for (uint j = 0; j < ptt->edge_count(); j++) { 55.58 + uint n1 = ptt->edge_target(j); 55.59 + if (visited->test_set(n1)) 55.60 + continue; 55.61 + switch(ptt->edge_type(j)) { 55.62 + case PointsToNode::PointsToEdge: 55.63 + add_pointsto_edge(ni, n1); 55.64 + if(n1 == _phantom_object) { 55.65 + // Special case - field set outside (globally escaping). 55.66 + ptn->set_escape_state(PointsToNode::GlobalEscape); 55.67 } 55.68 - } 55.69 + break; 55.70 + case PointsToNode::DeferredEdge: 55.71 + deferred_edges->append(n1); 55.72 + break; 55.73 + case PointsToNode::FieldEdge: 55.74 + assert(false, "invalid connection graph"); 55.75 + break; 55.76 } 55.77 } 55.78 } 55.79 @@ -1243,8 +1253,10 @@ 55.80 } 55.81 55.82 VectorSet ptset(Thread::current()->resource_area()); 55.83 - GrowableArray<Node*> alloc_worklist; 55.84 - GrowableArray<int> worklist; 55.85 + GrowableArray<Node*> alloc_worklist; 55.86 + GrowableArray<int> worklist; 55.87 + GrowableArray<uint> deferred_edges; 55.88 + VectorSet visited(Thread::current()->resource_area()); 55.89 55.90 // remove deferred edges from the graph and collect 55.91 // information we will need for type splitting 55.92 @@ -1254,7 +1266,7 @@ 55.93 PointsToNode::NodeType nt = ptn->node_type(); 55.94 Node *n = ptn->_node; 55.95 if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) { 55.96 - remove_deferred(ni); 55.97 + remove_deferred(ni, &deferred_edges, &visited); 55.98 if (n->is_AddP()) { 55.99 // If this AddP computes an address which may point to more that one 55.100 // object, nothing the address points to can be scalar replaceable.
56.1 --- a/src/share/vm/opto/escape.hpp Thu Apr 10 15:49:16 2008 -0400 56.2 +++ b/src/share/vm/opto/escape.hpp Fri Apr 11 09:56:35 2008 -0400 56.3 @@ -269,7 +269,7 @@ 56.4 // Remove outgoing deferred edges from the node referenced by "ni". 56.5 // Any outgoing edges from the target of the deferred edge are copied 56.6 // to "ni". 56.7 - void remove_deferred(uint ni); 56.8 + void remove_deferred(uint ni, GrowableArray<uint>* deferred_edges, VectorSet* visited); 56.9 56.10 Node_Array _node_map; // used for bookeeping during type splitting 56.11 // Used for the following purposes:
57.1 --- a/src/share/vm/opto/loopUnswitch.cpp Thu Apr 10 15:49:16 2008 -0400 57.2 +++ b/src/share/vm/opto/loopUnswitch.cpp Fri Apr 11 09:56:35 2008 -0400 57.3 @@ -51,6 +51,9 @@ 57.4 if( !LoopUnswitching ) { 57.5 return false; 57.6 } 57.7 + if (!_head->is_Loop()) { 57.8 + return false; 57.9 + } 57.10 uint nodes_left = MaxNodeLimit - phase->C->unique(); 57.11 if (2 * _body.size() > nodes_left) { 57.12 return false; // Too speculative if running low on nodes.
58.1 --- a/src/share/vm/opto/loopopts.cpp Thu Apr 10 15:49:16 2008 -0400 58.2 +++ b/src/share/vm/opto/loopopts.cpp Fri Apr 11 09:56:35 2008 -0400 58.3 @@ -2257,6 +2257,9 @@ 58.4 // 58.5 bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) { 58.6 58.7 + if (!loop->_head->is_Loop()) { 58.8 + return false; } 58.9 + 58.10 LoopNode *head = loop->_head->as_Loop(); 58.11 58.12 if (head->is_partial_peel_loop() || head->partial_peel_has_failed()) {
59.1 --- a/src/share/vm/opto/parse3.cpp Thu Apr 10 15:49:16 2008 -0400 59.2 +++ b/src/share/vm/opto/parse3.cpp Fri Apr 11 09:56:35 2008 -0400 59.3 @@ -408,7 +408,7 @@ 59.4 jint dim_con = find_int_con(length[j], -1); 59.5 expand_fanout *= dim_con; 59.6 expand_count += expand_fanout; // count the level-J sub-arrays 59.7 - if (dim_con < 0 59.8 + if (dim_con <= 0 59.9 || dim_con > expand_limit 59.10 || expand_count > expand_limit) { 59.11 expand_count = 0;
60.1 --- a/src/share/vm/opto/superword.cpp Thu Apr 10 15:49:16 2008 -0400 60.2 +++ b/src/share/vm/opto/superword.cpp Fri Apr 11 09:56:35 2008 -0400 60.3 @@ -65,6 +65,11 @@ 60.4 Node *cl_exit = cl->loopexit(); 60.5 if (cl_exit->in(0) != lpt->_head) return; 60.6 60.7 + // Make sure the are no extra control users of the loop backedge 60.8 + if (cl->back_control()->outcnt() != 1) { 60.9 + return; 60.10 + } 60.11 + 60.12 // Check for pre-loop ending with CountedLoopEnd(Bool(Cmp(x,Opaque1(limit)))) 60.13 CountedLoopEndNode* pre_end = get_pre_loop_end(cl); 60.14 if (pre_end == NULL) return;
61.1 --- a/src/share/vm/prims/forte.cpp Thu Apr 10 15:49:16 2008 -0400 61.2 +++ b/src/share/vm/prims/forte.cpp Fri Apr 11 09:56:35 2008 -0400 61.3 @@ -25,6 +25,20 @@ 61.4 # include "incls/_precompiled.incl" 61.5 # include "incls/_forte.cpp.incl" 61.6 61.7 +// These name match the names reported by the forte quality kit 61.8 +enum { 61.9 + ticks_no_Java_frame = 0, 61.10 + ticks_no_class_load = -1, 61.11 + ticks_GC_active = -2, 61.12 + ticks_unknown_not_Java = -3, 61.13 + ticks_not_walkable_not_Java = -4, 61.14 + ticks_unknown_Java = -5, 61.15 + ticks_not_walkable_Java = -6, 61.16 + ticks_unknown_state = -7, 61.17 + ticks_thread_exit = -8, 61.18 + ticks_deopt = -9, 61.19 + ticks_safepoint = -10 61.20 +}; 61.21 61.22 //------------------------------------------------------- 61.23 61.24 @@ -41,297 +55,29 @@ 61.25 }; 61.26 61.27 61.28 -static void forte_is_walkable_compiled_frame(frame* fr, RegisterMap* map, 61.29 +static void is_decipherable_compiled_frame(frame* fr, RegisterMap* map, 61.30 bool* is_compiled_p, bool* is_walkable_p); 61.31 -static bool forte_is_walkable_interpreted_frame(frame* fr, 61.32 - methodOop* method_p, int* bci_p); 61.33 +static bool is_decipherable_interpreted_frame(JavaThread* thread, 61.34 + frame* fr, 61.35 + methodOop* method_p, 61.36 + int* bci_p); 61.37 61.38 61.39 -// A Forte specific version of frame:safe_for_sender(). 61.40 -static bool forte_safe_for_sender(frame* fr, JavaThread *thread) { 61.41 - bool ret_value = false; // be pessimistic 61.42 61.43 -#ifdef COMPILER2 61.44 -#if defined(IA32) || defined(AMD64) 61.45 - { 61.46 - // This check is the same as the standard safe_for_sender() 61.47 - // on IA32 or AMD64 except that NULL FP values are tolerated 61.48 - // for C2. 61.49 - address sp = (address)fr->sp(); 61.50 - address fp = (address)fr->fp(); 61.51 - ret_value = sp != NULL && sp <= thread->stack_base() && 61.52 - sp >= thread->stack_base() - thread->stack_size() && 61.53 - (fp == NULL || (fp <= thread->stack_base() && 61.54 - fp >= thread->stack_base() - thread->stack_size())); 61.55 61.56 - // We used to use standard safe_for_sender() when we are supposed 61.57 - // to be executing Java code. However, that prevents us from 61.58 - // walking some intrinsic stacks so now we have to be more refined. 61.59 - // If we passed the above check and we have a NULL frame pointer 61.60 - // and we are supposed to be executing Java code, then we have a 61.61 - // couple of more checks to make. 61.62 - if (ret_value && fp == NULL && (thread->thread_state() == _thread_in_Java 61.63 - || thread->thread_state() == _thread_in_Java_trans)) { 61.64 +vframeStreamForte::vframeStreamForte(JavaThread *jt, 61.65 + frame fr, 61.66 + bool stop_at_java_call_stub) : vframeStreamCommon(jt) { 61.67 61.68 - if (fr->is_interpreted_frame()) { 61.69 - // interpreted frames don't really have a NULL frame pointer 61.70 - return false; 61.71 - } else if (CodeCache::find_blob(fr->pc()) == NULL) { 61.72 - // the NULL frame pointer should be associated with generated code 61.73 - return false; 61.74 - } 61.75 - } 61.76 - } 61.77 + _stop_at_java_call_stub = stop_at_java_call_stub; 61.78 + _frame = fr; 61.79 61.80 -#else // !(IA32 || AMD64) 61.81 - ret_value = fr->safe_for_sender(thread); 61.82 -#endif // IA32 || AMD64 61.83 + // We must always have a valid frame to start filling 61.84 61.85 -#else // !COMPILER2 61.86 - ret_value = fr->safe_for_sender(thread); 61.87 -#endif // COMPILER2 61.88 + bool filled_in = fill_from_frame(); 61.89 61.90 - if (!ret_value) { 61.91 - return ret_value; // not safe, nothing more to do 61.92 - } 61.93 + assert(filled_in, "invariant"); 61.94 61.95 - address sp1; 61.96 - 61.97 -#ifdef SPARC 61.98 - // On Solaris SPARC, when a compiler frame has an interpreted callee 61.99 - // the _interpreter_sp_adjustment field contains the adjustment to 61.100 - // this frame's SP made by that interpreted callee. 61.101 - // For AsyncGetCallTrace(), we need to verify that the resulting SP 61.102 - // is valid for the specified thread's stack. 61.103 - sp1 = (address)fr->sp(); 61.104 - address sp2 = (address)fr->unextended_sp(); 61.105 - 61.106 - // If the second SP is NULL, then the _interpreter_sp_adjustment 61.107 - // field simply adjusts this frame's SP to NULL and the frame is 61.108 - // not safe. This strange value can be set in the frame constructor 61.109 - // when our peek into the interpreted callee's adjusted value for 61.110 - // this frame's SP finds a NULL. This can happen when SIGPROF 61.111 - // catches us while we are creating the interpreter frame. 61.112 - // 61.113 - if (sp2 == NULL || 61.114 - 61.115 - // If the two SPs are different, then _interpreter_sp_adjustment 61.116 - // is non-zero and we need to validate the second SP. We invert 61.117 - // the range check from frame::safe_for_sender() and bail out 61.118 - // if the second SP is not safe. 61.119 - (sp1 != sp2 && !(sp2 <= thread->stack_base() 61.120 - && sp2 >= (thread->stack_base() - thread->stack_size())))) { 61.121 - return false; 61.122 - } 61.123 -#endif // SPARC 61.124 - 61.125 - if (fr->is_entry_frame()) { 61.126 - // This frame thinks it is an entry frame; we need to validate 61.127 - // the JavaCallWrapper pointer. 61.128 - // Note: frame::entry_frame_is_first() assumes that the 61.129 - // JavaCallWrapper has a non-NULL _anchor field. We don't 61.130 - // check that here (yet) since we've never seen a failure 61.131 - // due to a NULL _anchor field. 61.132 - // Update: Originally this check was done only for SPARC. However, 61.133 - // this failure has now been seen on C2 C86. I have no reason to 61.134 - // believe that this is not a general issue so I'm enabling the 61.135 - // check for all compilers on all supported platforms. 61.136 -#ifdef COMPILER2 61.137 -#if defined(IA32) || defined(AMD64) 61.138 - if (fr->fp() == NULL) { 61.139 - // C2 X86 allows NULL frame pointers, but if we have one then 61.140 - // we cannot call entry_frame_call_wrapper(). 61.141 - return false; 61.142 - } 61.143 -#endif // IA32 || AMD64 61.144 -#endif // COMPILER2 61.145 - 61.146 - sp1 = (address)fr->entry_frame_call_wrapper(); 61.147 - // We invert the range check from frame::safe_for_sender() and 61.148 - // bail out if the JavaCallWrapper * is not safe. 61.149 - if (!(sp1 <= thread->stack_base() 61.150 - && sp1 >= (thread->stack_base() - thread->stack_size()))) { 61.151 - return false; 61.152 - } 61.153 - } 61.154 - 61.155 - return ret_value; 61.156 -} 61.157 - 61.158 - 61.159 -// Unknown compiled frames have caused assertion failures on Solaris 61.160 -// X86. This code also detects unknown compiled frames on Solaris 61.161 -// SPARC, but no assertion failures have been observed. However, I'm 61.162 -// paranoid so I'm enabling this code whenever we have a compiler. 61.163 -// 61.164 -// Returns true if the specified frame is an unknown compiled frame 61.165 -// and false otherwise. 61.166 -static bool is_unknown_compiled_frame(frame* fr, JavaThread *thread) { 61.167 - bool ret_value = false; // be optimistic 61.168 - 61.169 - // This failure mode only occurs when the thread is in state 61.170 - // _thread_in_Java so we are okay for this check for any other 61.171 - // thread state. 61.172 - // 61.173 - // Note: _thread_in_Java does not always mean that the thread 61.174 - // is executing Java code. AsyncGetCallTrace() has caught 61.175 - // threads executing in JRT_LEAF() routines when the state 61.176 - // will also be _thread_in_Java. 61.177 - if (thread->thread_state() != _thread_in_Java) { 61.178 - return ret_value; 61.179 - } 61.180 - 61.181 - // This failure mode only occurs with compiled frames so we are 61.182 - // okay for this check for both entry and interpreted frames. 61.183 - if (fr->is_entry_frame() || fr->is_interpreted_frame()) { 61.184 - return ret_value; 61.185 - } 61.186 - 61.187 - // This failure mode only occurs when the compiled frame's PC 61.188 - // is in the code cache so we are okay for this check if the 61.189 - // PC is not in the code cache. 61.190 - CodeBlob* cb = CodeCache::find_blob(fr->pc()); 61.191 - if (cb == NULL) { 61.192 - return ret_value; 61.193 - } 61.194 - 61.195 - // We have compiled code in the code cache so it is time for 61.196 - // the final check: let's see if any frame type is set 61.197 - ret_value = !( 61.198 - // is_entry_frame() is checked above 61.199 - // testers that are a subset of is_entry_frame(): 61.200 - // is_first_frame() 61.201 - fr->is_java_frame() 61.202 - // testers that are a subset of is_java_frame(): 61.203 - // is_interpreted_frame() 61.204 - // is_compiled_frame() 61.205 - || fr->is_native_frame() 61.206 - || fr->is_runtime_frame() 61.207 - || fr->is_safepoint_blob_frame() 61.208 - ); 61.209 - 61.210 - // If there is no frame type set, then we have an unknown compiled 61.211 - // frame and sender() should not be called on it. 61.212 - 61.213 - return ret_value; 61.214 -} 61.215 - 61.216 -#define DebugNonSafepoints_IS_CLEARED \ 61.217 - (!FLAG_IS_DEFAULT(DebugNonSafepoints) && !DebugNonSafepoints) 61.218 - 61.219 -// if -XX:-DebugNonSafepoints, then top-frame will be skipped 61.220 -vframeStreamForte::vframeStreamForte(JavaThread *jt, frame fr, 61.221 - bool stop_at_java_call_stub) : vframeStreamCommon(jt) { 61.222 - _stop_at_java_call_stub = stop_at_java_call_stub; 61.223 - 61.224 - if (!DebugNonSafepoints_IS_CLEARED) { 61.225 - // decode the top frame fully 61.226 - // (usual case, if JVMTI is enabled) 61.227 - _frame = fr; 61.228 - } else { 61.229 - // skip top frame, as it may not be at safepoint 61.230 - // For AsyncGetCallTrace(), we extracted as much info from the top 61.231 - // frame as we could in forte_is_walkable_frame(). We also verified 61.232 - // forte_safe_for_sender() so this sender() call is safe. 61.233 - _frame = fr.sender(&_reg_map); 61.234 - } 61.235 - 61.236 - if (jt->thread_state() == _thread_in_Java && !fr.is_first_frame()) { 61.237 - bool sender_check = false; // assume sender is not safe 61.238 - 61.239 - if (forte_safe_for_sender(&_frame, jt)) { 61.240 - // If the initial sender frame is safe, then continue on with other 61.241 - // checks. The unsafe sender frame has been seen on Solaris X86 61.242 - // with both Compiler1 and Compiler2. It has not been seen on 61.243 - // Solaris SPARC, but seems like a good sanity check to have 61.244 - // anyway. 61.245 - 61.246 - // SIGPROF caught us in Java code and the current frame is not the 61.247 - // first frame so we should sanity check the sender frame. It is 61.248 - // possible for SIGPROF to catch us in the middle of making a call. 61.249 - // When that happens the current frame is actually a combination of 61.250 - // the real sender and some of the new call's info. We can't find 61.251 - // the real sender with such a current frame and things can get 61.252 - // confused. 61.253 - // 61.254 - // This sanity check has caught problems with the sender frame on 61.255 - // Solaris SPARC. So far Solaris X86 has not had a failure here. 61.256 - sender_check = _frame.is_entry_frame() 61.257 - // testers that are a subset of is_entry_frame(): 61.258 - // is_first_frame() 61.259 - || _frame.is_java_frame() 61.260 - // testers that are a subset of is_java_frame(): 61.261 - // is_interpreted_frame() 61.262 - // is_compiled_frame() 61.263 - || _frame.is_native_frame() 61.264 - || _frame.is_runtime_frame() 61.265 - || _frame.is_safepoint_blob_frame() 61.266 - ; 61.267 - 61.268 - // We need an additional sanity check on an initial interpreted 61.269 - // sender frame. This interpreted frame needs to be both walkable 61.270 - // and have a valid BCI. This is yet another variant of SIGPROF 61.271 - // catching us in the middle of making a call. 61.272 - if (sender_check && _frame.is_interpreted_frame()) { 61.273 - methodOop method = NULL; 61.274 - int bci = -1; 61.275 - 61.276 - if (!forte_is_walkable_interpreted_frame(&_frame, &method, &bci) 61.277 - || bci == -1) { 61.278 - sender_check = false; 61.279 - } 61.280 - } 61.281 - 61.282 - // We need an additional sanity check on an initial compiled 61.283 - // sender frame. This compiled frame also needs to be walkable. 61.284 - // This is yet another variant of SIGPROF catching us in the 61.285 - // middle of making a call. 61.286 - if (sender_check && !_frame.is_interpreted_frame()) { 61.287 - bool is_compiled, is_walkable; 61.288 - 61.289 - forte_is_walkable_compiled_frame(&_frame, &_reg_map, 61.290 - &is_compiled, &is_walkable); 61.291 - if (is_compiled && !is_walkable) { 61.292 - sender_check = false; 61.293 - } 61.294 - } 61.295 - } 61.296 - 61.297 - if (!sender_check) { 61.298 - // nothing else to try if we can't recognize the sender 61.299 - _mode = at_end_mode; 61.300 - return; 61.301 - } 61.302 - } 61.303 - 61.304 - int loop_count = 0; 61.305 - int loop_max = MaxJavaStackTraceDepth * 2; 61.306 - 61.307 - while (!fill_from_frame()) { 61.308 - _frame = _frame.sender(&_reg_map); 61.309 - 61.310 -#ifdef COMPILER2 61.311 -#if defined(IA32) || defined(AMD64) 61.312 - // Stress testing on C2 X86 has shown a periodic problem with 61.313 - // the sender() call below. The initial _frame that we have on 61.314 - // entry to the loop has already passed forte_safe_for_sender() 61.315 - // so we only check frames after it. 61.316 - if (!forte_safe_for_sender(&_frame, _thread)) { 61.317 - _mode = at_end_mode; 61.318 - return; 61.319 - } 61.320 -#endif // IA32 || AMD64 61.321 -#endif // COMPILER2 61.322 - 61.323 - if (++loop_count >= loop_max) { 61.324 - // We have looped more than twice the number of possible 61.325 - // Java frames. This indicates that we are trying to walk 61.326 - // a stack that is in the middle of being constructed and 61.327 - // it is self referential. 61.328 - _mode = at_end_mode; 61.329 - return; 61.330 - } 61.331 - } 61.332 } 61.333 61.334 61.335 @@ -358,95 +104,57 @@ 61.336 61.337 do { 61.338 61.339 -#if defined(COMPILER1) && defined(SPARC) 61.340 - bool prevIsInterpreted = _frame.is_interpreted_frame(); 61.341 -#endif // COMPILER1 && SPARC 61.342 + loop_count++; 61.343 61.344 - _frame = _frame.sender(&_reg_map); 61.345 + // By the time we get here we should never see unsafe but better 61.346 + // safe then segv'd 61.347 61.348 - if (!forte_safe_for_sender(&_frame, _thread)) { 61.349 + if (loop_count > loop_max || !_frame.safe_for_sender(_thread)) { 61.350 _mode = at_end_mode; 61.351 return; 61.352 } 61.353 61.354 -#if defined(COMPILER1) && defined(SPARC) 61.355 - if (prevIsInterpreted) { 61.356 - // previous callee was interpreted and may require a special check 61.357 - if (_frame.is_compiled_frame() && _frame.cb()->is_compiled_by_c1()) { 61.358 - // compiled sender called interpreted callee so need one more check 61.359 - bool is_compiled, is_walkable; 61.360 + _frame = _frame.sender(&_reg_map); 61.361 61.362 - // sanity check the compiled sender frame 61.363 - forte_is_walkable_compiled_frame(&_frame, &_reg_map, 61.364 - &is_compiled, &is_walkable); 61.365 - assert(is_compiled, "sanity check"); 61.366 - if (!is_walkable) { 61.367 - // compiled sender frame is not walkable so bail out 61.368 - _mode = at_end_mode; 61.369 - return; 61.370 - } 61.371 - } 61.372 - } 61.373 -#endif // COMPILER1 && SPARC 61.374 - 61.375 - if (++loop_count >= loop_max) { 61.376 - // We have looped more than twice the number of possible 61.377 - // Java frames. This indicates that we are trying to walk 61.378 - // a stack that is in the middle of being constructed and 61.379 - // it is self referential. 61.380 - _mode = at_end_mode; 61.381 - return; 61.382 - } 61.383 } while (!fill_from_frame()); 61.384 } 61.385 61.386 -// Determine if 'fr' is a walkable, compiled frame. 61.387 -// *is_compiled_p is set to true if the frame is compiled and if it 61.388 -// is, then *is_walkable_p is set to true if it is also walkable. 61.389 -static void forte_is_walkable_compiled_frame(frame* fr, RegisterMap* map, 61.390 - bool* is_compiled_p, bool* is_walkable_p) { 61.391 +// Determine if 'fr' is a decipherable compiled frame. We are already 61.392 +// assured that fr is for a java nmethod. 61.393 61.394 - *is_compiled_p = false; 61.395 - *is_walkable_p = false; 61.396 +static bool is_decipherable_compiled_frame(frame* fr) { 61.397 61.398 - CodeBlob* cb = CodeCache::find_blob(fr->pc()); 61.399 - if (cb != NULL && 61.400 - cb->is_nmethod() && 61.401 - ((nmethod*)cb)->is_java_method()) { 61.402 - // frame is compiled and executing a Java method 61.403 - *is_compiled_p = true; 61.404 + assert(fr->cb() != NULL && fr->cb()->is_nmethod(), "invariant"); 61.405 + nmethod* nm = (nmethod*) fr->cb(); 61.406 + assert(nm->is_java_method(), "invariant"); 61.407 61.408 - // Increment PC because the PcDesc we want is associated with 61.409 - // the *end* of the instruction, and pc_desc_near searches 61.410 - // forward to the first matching PC after the probe PC. 61.411 - PcDesc* pc_desc = NULL; 61.412 - if (!DebugNonSafepoints_IS_CLEARED) { 61.413 - // usual case: look for any safepoint near the sampled PC 61.414 - address probe_pc = fr->pc() + 1; 61.415 - pc_desc = ((nmethod*) cb)->pc_desc_near(probe_pc); 61.416 - } else { 61.417 - // reduced functionality: only recognize PCs immediately after calls 61.418 - pc_desc = ((nmethod*) cb)->pc_desc_at(fr->pc()); 61.419 + // First try and find an exact PcDesc 61.420 + 61.421 + PcDesc* pc_desc = nm->pc_desc_at(fr->pc()); 61.422 + 61.423 + // Did we find a useful PcDesc? 61.424 + if (pc_desc != NULL && 61.425 + pc_desc->scope_decode_offset() == DebugInformationRecorder::serialized_null) { 61.426 + 61.427 + address probe_pc = fr->pc() + 1; 61.428 + pc_desc = nm->pc_desc_near(probe_pc); 61.429 + 61.430 + // Now do we have a useful PcDesc? 61.431 + 61.432 + if (pc_desc != NULL && 61.433 + pc_desc->scope_decode_offset() == DebugInformationRecorder::serialized_null) { 61.434 + // No debug information available for this pc 61.435 + // vframeStream would explode if we try and walk the frames. 61.436 + return false; 61.437 } 61.438 - if (pc_desc != NULL && (pc_desc->scope_decode_offset() 61.439 - == DebugInformationRecorder::serialized_null)) { 61.440 - pc_desc = NULL; 61.441 - } 61.442 - if (pc_desc != NULL) { 61.443 - // it has a PcDesc so the frame is also walkable 61.444 - *is_walkable_p = true; 61.445 - if (!DebugNonSafepoints_IS_CLEARED) { 61.446 - // Normalize the PC to the one associated exactly with 61.447 - // this PcDesc, so that subsequent stack-walking queries 61.448 - // need not be approximate: 61.449 - fr->set_pc(pc_desc->real_pc((nmethod*) cb)); 61.450 - } 61.451 - } 61.452 - // Implied else: this compiled frame has no PcDesc, i.e., contains 61.453 - // a frameless stub such as C1 method exit, so it is not walkable. 61.454 + 61.455 + // This PcDesc is useful however we must adjust the frame's pc 61.456 + // so that the vframeStream lookups will use this same pc 61.457 + 61.458 + fr->set_pc(pc_desc->real_pc(nm)); 61.459 } 61.460 - // Implied else: this isn't a compiled frame so it isn't a 61.461 - // walkable, compiled frame. 61.462 + 61.463 + return true; 61.464 } 61.465 61.466 // Determine if 'fr' is a walkable interpreted frame. Returns false 61.467 @@ -457,159 +165,189 @@ 61.468 // Note: this method returns true when a valid Java method is found 61.469 // even if a valid BCI cannot be found. 61.470 61.471 -static bool forte_is_walkable_interpreted_frame(frame* fr, 61.472 - methodOop* method_p, int* bci_p) { 61.473 +static bool is_decipherable_interpreted_frame(JavaThread* thread, 61.474 + frame* fr, 61.475 + methodOop* method_p, 61.476 + int* bci_p) { 61.477 assert(fr->is_interpreted_frame(), "just checking"); 61.478 61.479 // top frame is an interpreted frame 61.480 // check if it is walkable (i.e. valid methodOop and valid bci) 61.481 - if (fr->is_interpreted_frame_valid()) { 61.482 - if (fr->fp() != NULL) { 61.483 - // access address in order not to trigger asserts that 61.484 - // are built in interpreter_frame_method function 61.485 - methodOop method = *fr->interpreter_frame_method_addr(); 61.486 - if (Universe::heap()->is_valid_method(method)) { 61.487 - intptr_t bcx = fr->interpreter_frame_bcx(); 61.488 - int bci = method->validate_bci_from_bcx(bcx); 61.489 - // note: bci is set to -1 if not a valid bci 61.490 - *method_p = method; 61.491 - *bci_p = bci; 61.492 - return true; 61.493 - } 61.494 - } 61.495 + 61.496 + // Because we may be racing a gc thread the method and/or bci 61.497 + // of a valid interpreter frame may look bad causing us to 61.498 + // fail the is_interpreted_frame_valid test. If the thread 61.499 + // is in any of the following states we are assured that the 61.500 + // frame is in fact valid and we must have hit the race. 61.501 + 61.502 + JavaThreadState state = thread->thread_state(); 61.503 + bool known_valid = (state == _thread_in_native || 61.504 + state == _thread_in_vm || 61.505 + state == _thread_blocked ); 61.506 + 61.507 + if (known_valid || fr->is_interpreted_frame_valid(thread)) { 61.508 + 61.509 + // The frame code should completely validate the frame so that 61.510 + // references to methodOop and bci are completely safe to access 61.511 + // If they aren't the frame code should be fixed not this 61.512 + // code. However since gc isn't locked out the values could be 61.513 + // stale. This is a race we can never completely win since we can't 61.514 + // lock out gc so do one last check after retrieving their values 61.515 + // from the frame for additional safety 61.516 + 61.517 + methodOop method = fr->interpreter_frame_method(); 61.518 + 61.519 + // We've at least found a method. 61.520 + // NOTE: there is something to be said for the approach that 61.521 + // if we don't find a valid bci then the method is not likely 61.522 + // a valid method. Then again we may have caught an interpreter 61.523 + // frame in the middle of construction and the bci field is 61.524 + // not yet valid. 61.525 + 61.526 + *method_p = method; 61.527 + 61.528 + // See if gc may have invalidated method since we validated frame 61.529 + 61.530 + if (!Universe::heap()->is_valid_method(method)) return false; 61.531 + 61.532 + intptr_t bcx = fr->interpreter_frame_bcx(); 61.533 + 61.534 + int bci = method->validate_bci_from_bcx(bcx); 61.535 + 61.536 + // note: bci is set to -1 if not a valid bci 61.537 + *bci_p = bci; 61.538 + return true; 61.539 } 61.540 + 61.541 return false; 61.542 } 61.543 61.544 61.545 -// Determine if 'fr' can be used to find a walkable frame. Returns 61.546 -// false if a walkable frame cannot be found. *walkframe_p, *method_p, 61.547 -// and *bci_p are not set when false is returned. Returns true if a 61.548 -// walkable frame is returned via *walkframe_p. *method_p is non-NULL 61.549 -// if the returned frame was executing a Java method. *bci_p is != -1 61.550 -// if a valid BCI in the Java method could be found. 61.551 +// Determine if 'fr' can be used to find an initial Java frame. 61.552 +// Return false if it can not find a fully decipherable Java frame 61.553 +// (in other words a frame that isn't safe to use in a vframe stream). 61.554 +// Obviously if it can't even find a Java frame false will also be returned. 61.555 // 61.556 -// *walkframe_p will be used by vframeStreamForte as the initial 61.557 -// frame for walking the stack. Currently the initial frame is 61.558 -// skipped by vframeStreamForte because we inherited the logic from 61.559 -// the vframeStream class. This needs to be revisited in the future. 61.560 -static bool forte_is_walkable_frame(JavaThread* thread, frame* fr, 61.561 - frame* walkframe_p, methodOop* method_p, int* bci_p) { 61.562 +// If we find a Java frame decipherable or not then by definition we have 61.563 +// identified a method and that will be returned to the caller via method_p. 61.564 +// If we can determine a bci that is returned also. (Hmm is it possible 61.565 +// to return a method and bci and still return false? ) 61.566 +// 61.567 +// The initial Java frame we find (if any) is return via initial_frame_p. 61.568 +// 61.569 61.570 - if (!forte_safe_for_sender(fr, thread) 61.571 - || is_unknown_compiled_frame(fr, thread) 61.572 - ) { 61.573 - // If the initial frame is not safe, then bail out. So far this 61.574 - // has only been seen on Solaris X86 with Compiler2, but it seems 61.575 - // like a great initial sanity check. 61.576 - return false; 61.577 +static bool find_initial_Java_frame(JavaThread* thread, 61.578 + frame* fr, 61.579 + frame* initial_frame_p, 61.580 + methodOop* method_p, 61.581 + int* bci_p) { 61.582 + 61.583 + // It is possible that for a frame containing an nmethod 61.584 + // we can capture the method but no bci. If we get no 61.585 + // bci the frame isn't walkable but the method is usable. 61.586 + // Therefore we init the returned methodOop to NULL so the 61.587 + // caller can make the distinction. 61.588 + 61.589 + *method_p = NULL; 61.590 + 61.591 + // On the initial call to this method the frame we get may not be 61.592 + // recognizable to us. This should only happen if we are in a JRT_LEAF 61.593 + // or something called by a JRT_LEAF method. 61.594 + 61.595 + 61.596 + 61.597 + frame candidate = *fr; 61.598 + 61.599 + // If the starting frame we were given has no codeBlob associated with 61.600 + // it see if we can find such a frame because only frames with codeBlobs 61.601 + // are possible Java frames. 61.602 + 61.603 + if (fr->cb() == NULL) { 61.604 + 61.605 + // See if we can find a useful frame 61.606 + int loop_count; 61.607 + int loop_max = MaxJavaStackTraceDepth * 2; 61.608 + RegisterMap map(thread, false); 61.609 + 61.610 + for (loop_count = 0; loop_count < loop_max; loop_count++) { 61.611 + if (!candidate.safe_for_sender(thread)) return false; 61.612 + candidate = candidate.sender(&map); 61.613 + if (candidate.cb() != NULL) break; 61.614 + } 61.615 + if (candidate.cb() == NULL) return false; 61.616 } 61.617 61.618 - if (fr->is_first_frame()) { 61.619 - // If initial frame is frame from StubGenerator and there is no 61.620 - // previous anchor, there are no java frames yet 61.621 - return false; 61.622 + // We have a frame known to be in the codeCache 61.623 + // We will hopefully be able to figure out something to do with it. 61.624 + int loop_count; 61.625 + int loop_max = MaxJavaStackTraceDepth * 2; 61.626 + RegisterMap map(thread, false); 61.627 + 61.628 + for (loop_count = 0; loop_count < loop_max; loop_count++) { 61.629 + 61.630 + if (candidate.is_first_frame()) { 61.631 + // If initial frame is frame from StubGenerator and there is no 61.632 + // previous anchor, there are no java frames associated with a method 61.633 + return false; 61.634 + } 61.635 + 61.636 + if (candidate.is_interpreted_frame()) { 61.637 + if (is_decipherable_interpreted_frame(thread, &candidate, method_p, bci_p)) { 61.638 + *initial_frame_p = candidate; 61.639 + return true; 61.640 + } 61.641 + 61.642 + // Hopefully we got some data 61.643 + return false; 61.644 + } 61.645 + 61.646 + if (candidate.cb()->is_nmethod()) { 61.647 + 61.648 + nmethod* nm = (nmethod*) candidate.cb(); 61.649 + *method_p = nm->method(); 61.650 + 61.651 + // If the frame isn't fully decipherable then the default 61.652 + // value for the bci is a signal that we don't have a bci. 61.653 + // If we have a decipherable frame this bci value will 61.654 + // not be used. 61.655 + 61.656 + *bci_p = -1; 61.657 + 61.658 + *initial_frame_p = candidate; 61.659 + 61.660 + // Native wrapper code is trivial to decode by vframeStream 61.661 + 61.662 + if (nm->is_native_method()) return true; 61.663 + 61.664 + // If it isn't decipherable then we have found a pc that doesn't 61.665 + // have a PCDesc that can get us a bci however we did find 61.666 + // a method 61.667 + 61.668 + if (!is_decipherable_compiled_frame(&candidate)) { 61.669 + return false; 61.670 + } 61.671 + 61.672 + // is_decipherable_compiled_frame may modify candidate's pc 61.673 + *initial_frame_p = candidate; 61.674 + 61.675 + return true; 61.676 + } 61.677 + 61.678 + // Must be some stub frame that we don't care about 61.679 + 61.680 + if (!candidate.safe_for_sender(thread)) return false; 61.681 + candidate = candidate.sender(&map); 61.682 + 61.683 + // If it isn't in the code cache something is wrong 61.684 + // since once we find a frame in the code cache they 61.685 + // all should be there. 61.686 + 61.687 + if (candidate.cb() == NULL) return false; 61.688 + 61.689 } 61.690 61.691 - if (fr->is_interpreted_frame()) { 61.692 - if (forte_is_walkable_interpreted_frame(fr, method_p, bci_p)) { 61.693 - *walkframe_p = *fr; 61.694 - return true; 61.695 - } 61.696 - return false; 61.697 - } 61.698 + return false; 61.699 61.700 - // At this point we have something other than a first frame or an 61.701 - // interpreted frame. 61.702 - 61.703 - methodOop method = NULL; 61.704 - frame candidate = *fr; 61.705 - 61.706 - // If we loop more than twice the number of possible Java 61.707 - // frames, then this indicates that we are trying to walk 61.708 - // a stack that is in the middle of being constructed and 61.709 - // it is self referential. So far this problem has only 61.710 - // been seen on Solaris X86 Compiler2, but it seems like 61.711 - // a good robustness fix for all platforms. 61.712 - 61.713 - int loop_count; 61.714 - int loop_max = MaxJavaStackTraceDepth * 2; 61.715 - 61.716 - for (loop_count = 0; loop_count < loop_max; loop_count++) { 61.717 - // determine if the candidate frame is executing a Java method 61.718 - if (CodeCache::contains(candidate.pc())) { 61.719 - // candidate is a compiled frame or stub routine 61.720 - CodeBlob* cb = CodeCache::find_blob(candidate.pc()); 61.721 - 61.722 - if (cb->is_nmethod()) { 61.723 - method = ((nmethod *)cb)->method(); 61.724 - } 61.725 - } // end if CodeCache has our PC 61.726 - 61.727 - RegisterMap map(thread, false); 61.728 - 61.729 - // we have a Java frame that seems reasonable 61.730 - if (method != NULL && candidate.is_java_frame() 61.731 - && candidate.sp() != NULL && candidate.pc() != NULL) { 61.732 - // we need to sanity check the candidate further 61.733 - bool is_compiled, is_walkable; 61.734 - 61.735 - forte_is_walkable_compiled_frame(&candidate, &map, &is_compiled, 61.736 - &is_walkable); 61.737 - if (is_compiled) { 61.738 - // At this point, we know we have a compiled Java frame with 61.739 - // method information that we want to return. We don't check 61.740 - // the is_walkable flag here because that flag pertains to 61.741 - // vframeStreamForte work that is done after we are done here. 61.742 - break; 61.743 - } 61.744 - } 61.745 - 61.746 - // At this point, the candidate doesn't work so try the sender. 61.747 - 61.748 - // For AsyncGetCallTrace() we cannot assume there is a sender 61.749 - // for the initial frame. The initial forte_safe_for_sender() call 61.750 - // and check for is_first_frame() is done on entry to this method. 61.751 - candidate = candidate.sender(&map); 61.752 - if (!forte_safe_for_sender(&candidate, thread)) { 61.753 - 61.754 -#ifdef COMPILER2 61.755 -#if defined(IA32) || defined(AMD64) 61.756 - // C2 on X86 can use the ebp register as a general purpose register 61.757 - // which can cause the candidate to fail theforte_safe_for_sender() 61.758 - // above. We try one more time using a NULL frame pointer (fp). 61.759 - 61.760 - candidate = frame(candidate.sp(), NULL, candidate.pc()); 61.761 - if (!forte_safe_for_sender(&candidate, thread)) { 61.762 -#endif // IA32 || AMD64 61.763 -#endif // COMPILER2 61.764 - 61.765 - return false; 61.766 - 61.767 -#ifdef COMPILER2 61.768 -#if defined(IA32) || defined(AMD64) 61.769 - } // end forte_safe_for_sender retry with NULL fp 61.770 -#endif // IA32 || AMD64 61.771 -#endif // COMPILER2 61.772 - 61.773 - } // end first forte_safe_for_sender check 61.774 - 61.775 - if (candidate.is_first_frame() 61.776 - || is_unknown_compiled_frame(&candidate, thread)) { 61.777 - return false; 61.778 - } 61.779 - } // end for loop_count 61.780 - 61.781 - if (method == NULL) { 61.782 - // If we didn't get any method info from the candidate, then 61.783 - // we have nothing to return so bail out. 61.784 - return false; 61.785 - } 61.786 - 61.787 - *walkframe_p = candidate; 61.788 - *method_p = method; 61.789 - *bci_p = -1; 61.790 - return true; 61.791 } 61.792 61.793 61.794 @@ -627,10 +365,12 @@ 61.795 } ASGCT_CallTrace; 61.796 61.797 static void forte_fill_call_trace_given_top(JavaThread* thd, 61.798 - ASGCT_CallTrace* trace, int depth, frame top_frame) { 61.799 + ASGCT_CallTrace* trace, 61.800 + int depth, 61.801 + frame top_frame) { 61.802 NoHandleMark nhm; 61.803 61.804 - frame walkframe; 61.805 + frame initial_Java_frame; 61.806 methodOop method; 61.807 int bci; 61.808 int count; 61.809 @@ -638,48 +378,51 @@ 61.810 count = 0; 61.811 assert(trace->frames != NULL, "trace->frames must be non-NULL"); 61.812 61.813 - if (!forte_is_walkable_frame(thd, &top_frame, &walkframe, &method, &bci)) { 61.814 - // return if no walkable frame is found 61.815 + bool fully_decipherable = find_initial_Java_frame(thd, &top_frame, &initial_Java_frame, &method, &bci); 61.816 + 61.817 + // The frame might not be walkable but still recovered a method 61.818 + // (e.g. an nmethod with no scope info for the pc 61.819 + 61.820 + if (method == NULL) return; 61.821 + 61.822 + CollectedHeap* ch = Universe::heap(); 61.823 + 61.824 + // The method is not stored GC safe so see if GC became active 61.825 + // after we entered AsyncGetCallTrace() and before we try to 61.826 + // use the methodOop. 61.827 + // Yes, there is still a window after this check and before 61.828 + // we use methodOop below, but we can't lock out GC so that 61.829 + // has to be an acceptable risk. 61.830 + if (!ch->is_valid_method(method)) { 61.831 + trace->num_frames = ticks_GC_active; // -2 61.832 return; 61.833 } 61.834 61.835 - CollectedHeap* ch = Universe::heap(); 61.836 + // We got a Java frame however it isn't fully decipherable 61.837 + // so it won't necessarily be safe to use it for the 61.838 + // initial frame in the vframe stream. 61.839 61.840 - if (method != NULL) { 61.841 - // The method is not stored GC safe so see if GC became active 61.842 - // after we entered AsyncGetCallTrace() and before we try to 61.843 - // use the methodOop. 61.844 - // Yes, there is still a window after this check and before 61.845 - // we use methodOop below, but we can't lock out GC so that 61.846 - // has to be an acceptable risk. 61.847 - if (!ch->is_valid_method(method)) { 61.848 - trace->num_frames = -2; 61.849 - return; 61.850 + if (!fully_decipherable) { 61.851 + // Take whatever method the top-frame decoder managed to scrape up. 61.852 + // We look further at the top frame only if non-safepoint 61.853 + // debugging information is available. 61.854 + count++; 61.855 + trace->num_frames = count; 61.856 + trace->frames[0].method_id = method->find_jmethod_id_or_null(); 61.857 + if (!method->is_native()) { 61.858 + trace->frames[0].lineno = bci; 61.859 + } else { 61.860 + trace->frames[0].lineno = -3; 61.861 } 61.862 61.863 - if (DebugNonSafepoints_IS_CLEARED) { 61.864 - // Take whatever method the top-frame decoder managed to scrape up. 61.865 - // We look further at the top frame only if non-safepoint 61.866 - // debugging information is available. 61.867 - count++; 61.868 - trace->num_frames = count; 61.869 - trace->frames[0].method_id = method->find_jmethod_id_or_null(); 61.870 - if (!method->is_native()) { 61.871 - trace->frames[0].lineno = bci; 61.872 - } else { 61.873 - trace->frames[0].lineno = -3; 61.874 - } 61.875 - } 61.876 + if (!initial_Java_frame.safe_for_sender(thd)) return; 61.877 + 61.878 + RegisterMap map(thd, false); 61.879 + initial_Java_frame = initial_Java_frame.sender(&map); 61.880 } 61.881 61.882 - // check has_last_Java_frame() after looking at the top frame 61.883 - // which may be an interpreted Java frame. 61.884 - if (!thd->has_last_Java_frame() && method == NULL) { 61.885 - trace->num_frames = 0; 61.886 - return; 61.887 - } 61.888 + vframeStreamForte st(thd, initial_Java_frame, false); 61.889 61.890 - vframeStreamForte st(thd, walkframe, false); 61.891 for (; !st.at_end() && count < depth; st.forte_next(), count++) { 61.892 bci = st.bci(); 61.893 method = st.method(); 61.894 @@ -693,7 +436,7 @@ 61.895 if (!ch->is_valid_method(method)) { 61.896 // we throw away everything we've gathered in this sample since 61.897 // none of it is safe 61.898 - trace->num_frames = -2; 61.899 + trace->num_frames = ticks_GC_active; // -2 61.900 return; 61.901 } 61.902 61.903 @@ -765,6 +508,11 @@ 61.904 61.905 extern "C" { 61.906 void AsyncGetCallTrace(ASGCT_CallTrace *trace, jint depth, void* ucontext) { 61.907 + 61.908 +// This is if'd out because we no longer use thread suspension. 61.909 +// However if someone wanted to backport this to a 5.0 jvm then this 61.910 +// code would be important. 61.911 +#if 0 61.912 if (SafepointSynchronize::is_synchronizing()) { 61.913 // The safepoint mechanism is trying to synchronize all the threads. 61.914 // Since this can involve thread suspension, it is not safe for us 61.915 @@ -774,9 +522,10 @@ 61.916 // are suspended while holding a resource and another thread blocks 61.917 // on that resource in the SIGPROF handler, then we will have a 61.918 // three-thread deadlock (VMThread, this thread, the other thread). 61.919 - trace->num_frames = -10; 61.920 + trace->num_frames = ticks_safepoint; // -10 61.921 return; 61.922 } 61.923 +#endif 61.924 61.925 JavaThread* thread; 61.926 61.927 @@ -785,13 +534,13 @@ 61.928 thread->is_exiting()) { 61.929 61.930 // bad env_id, thread has exited or thread is exiting 61.931 - trace->num_frames = -8; 61.932 + trace->num_frames = ticks_thread_exit; // -8 61.933 return; 61.934 } 61.935 61.936 if (thread->in_deopt_handler()) { 61.937 // thread is in the deoptimization handler so return no frames 61.938 - trace->num_frames = -9; 61.939 + trace->num_frames = ticks_deopt; // -9 61.940 return; 61.941 } 61.942 61.943 @@ -799,12 +548,12 @@ 61.944 "AsyncGetCallTrace must be called by the current interrupted thread"); 61.945 61.946 if (!JvmtiExport::should_post_class_load()) { 61.947 - trace->num_frames = -1; 61.948 + trace->num_frames = ticks_no_class_load; // -1 61.949 return; 61.950 } 61.951 61.952 if (Universe::heap()->is_gc_active()) { 61.953 - trace->num_frames = -2; 61.954 + trace->num_frames = ticks_GC_active; // -2 61.955 return; 61.956 } 61.957 61.958 @@ -827,14 +576,22 @@ 61.959 61.960 // param isInJava == false - indicate we aren't in Java code 61.961 if (!thread->pd_get_top_frame_for_signal_handler(&fr, ucontext, false)) { 61.962 + trace->num_frames = ticks_unknown_not_Java; // -3 unknown frame 61.963 + } else { 61.964 if (!thread->has_last_Java_frame()) { 61.965 - trace->num_frames = 0; // no Java frames 61.966 + trace->num_frames = 0; // No Java frames 61.967 } else { 61.968 - trace->num_frames = -3; // unknown frame 61.969 + trace->num_frames = ticks_not_walkable_not_Java; // -4 non walkable frame by default 61.970 + forte_fill_call_trace_given_top(thread, trace, depth, fr); 61.971 + 61.972 + // This assert would seem to be valid but it is not. 61.973 + // It would be valid if we weren't possibly racing a gc 61.974 + // thread. A gc thread can make a valid interpreted frame 61.975 + // look invalid. It's a small window but it does happen. 61.976 + // The assert is left here commented out as a reminder. 61.977 + // assert(trace->num_frames != ticks_not_walkable_not_Java, "should always be walkable"); 61.978 + 61.979 } 61.980 - } else { 61.981 - trace->num_frames = -4; // non walkable frame by default 61.982 - forte_fill_call_trace_given_top(thread, trace, depth, fr); 61.983 } 61.984 } 61.985 break; 61.986 @@ -845,16 +602,16 @@ 61.987 61.988 // param isInJava == true - indicate we are in Java code 61.989 if (!thread->pd_get_top_frame_for_signal_handler(&fr, ucontext, true)) { 61.990 - trace->num_frames = -5; // unknown frame 61.991 + trace->num_frames = ticks_unknown_Java; // -5 unknown frame 61.992 } else { 61.993 - trace->num_frames = -6; // non walkable frame by default 61.994 + trace->num_frames = ticks_not_walkable_Java; // -6, non walkable frame by default 61.995 forte_fill_call_trace_given_top(thread, trace, depth, fr); 61.996 } 61.997 } 61.998 break; 61.999 default: 61.1000 // Unknown thread state 61.1001 - trace->num_frames = -7; 61.1002 + trace->num_frames = ticks_unknown_state; // -7 61.1003 break; 61.1004 } 61.1005 }
62.1 --- a/src/share/vm/runtime/fprofiler.cpp Thu Apr 10 15:49:16 2008 -0400 62.2 +++ b/src/share/vm/runtime/fprofiler.cpp Fri Apr 11 09:56:35 2008 -0400 62.3 @@ -924,29 +924,23 @@ 62.4 FlatProfiler::record_thread_ticks(); 62.5 } 62.6 62.7 -void ThreadProfiler::record_interpreted_tick(frame fr, TickPosition where, int* ticks) { 62.8 +void ThreadProfiler::record_interpreted_tick(JavaThread* thread, frame fr, TickPosition where, int* ticks) { 62.9 FlatProfiler::all_int_ticks++; 62.10 if (!FlatProfiler::full_profile()) { 62.11 return; 62.12 } 62.13 62.14 - if (!fr.is_interpreted_frame_valid()) { 62.15 + if (!fr.is_interpreted_frame_valid(thread)) { 62.16 // tick came at a bad time 62.17 interpreter_ticks += 1; 62.18 FlatProfiler::interpreter_ticks += 1; 62.19 return; 62.20 } 62.21 62.22 - methodOop method = NULL; 62.23 - if (fr.fp() != NULL) { 62.24 - method = *fr.interpreter_frame_method_addr(); 62.25 - } 62.26 - if (!Universe::heap()->is_valid_method(method)) { 62.27 - // tick came at a bad time, stack frame not initialized correctly 62.28 - interpreter_ticks += 1; 62.29 - FlatProfiler::interpreter_ticks += 1; 62.30 - return; 62.31 - } 62.32 + // The frame has been fully validated so we can trust the method and bci 62.33 + 62.34 + methodOop method = *fr.interpreter_frame_method_addr(); 62.35 + 62.36 interpreted_update(method, where); 62.37 62.38 // update byte code table 62.39 @@ -997,7 +991,7 @@ 62.40 // The tick happend in real code -> non VM code 62.41 if (fr.is_interpreted_frame()) { 62.42 interval_data_ref()->inc_interpreted(); 62.43 - record_interpreted_tick(fr, tp_code, FlatProfiler::bytecode_ticks); 62.44 + record_interpreted_tick(thread, fr, tp_code, FlatProfiler::bytecode_ticks); 62.45 return; 62.46 } 62.47 62.48 @@ -1028,7 +1022,7 @@ 62.49 // The tick happend in VM code 62.50 interval_data_ref()->inc_native(); 62.51 if (fr.is_interpreted_frame()) { 62.52 - record_interpreted_tick(fr, tp_native, FlatProfiler::bytecode_ticks_stub); 62.53 + record_interpreted_tick(thread, fr, tp_native, FlatProfiler::bytecode_ticks_stub); 62.54 return; 62.55 } 62.56 if (CodeCache::contains(fr.pc())) {
63.1 --- a/src/share/vm/runtime/fprofiler.hpp Thu Apr 10 15:49:16 2008 -0400 63.2 +++ b/src/share/vm/runtime/fprofiler.hpp Fri Apr 11 09:56:35 2008 -0400 63.3 @@ -135,7 +135,7 @@ 63.4 ProfilerNode** table; 63.5 63.6 private: 63.7 - void record_interpreted_tick(frame fr, TickPosition where, int* ticks); 63.8 + void record_interpreted_tick(JavaThread* thread, frame fr, TickPosition where, int* ticks); 63.9 void record_compiled_tick (JavaThread* thread, frame fr, TickPosition where); 63.10 void interpreted_update(methodOop method, TickPosition where); 63.11 void compiled_update (methodOop method, TickPosition where);
64.1 --- a/src/share/vm/runtime/frame.hpp Thu Apr 10 15:49:16 2008 -0400 64.2 +++ b/src/share/vm/runtime/frame.hpp Fri Apr 11 09:56:35 2008 -0400 64.3 @@ -108,7 +108,7 @@ 64.4 bool is_first_frame() const; // oldest frame? (has no sender) 64.5 bool is_first_java_frame() const; // same for Java frame 64.6 64.7 - bool is_interpreted_frame_valid() const; // performs sanity checks on interpreted frames. 64.8 + bool is_interpreted_frame_valid(JavaThread* thread) const; // performs sanity checks on interpreted frames. 64.9 64.10 // tells whether this frame is marked for deoptimization 64.11 bool should_be_deoptimized() const;
65.1 --- a/src/share/vm/runtime/globals.cpp Thu Apr 10 15:49:16 2008 -0400 65.2 +++ b/src/share/vm/runtime/globals.cpp Fri Apr 11 09:56:35 2008 -0400 65.3 @@ -68,18 +68,20 @@ 65.4 if (is_uintx()) st->print("%-16lu", get_uintx()); 65.5 if (is_ccstr()) { 65.6 const char* cp = get_ccstr(); 65.7 - const char* eol; 65.8 - while ((eol = strchr(cp, '\n')) != NULL) { 65.9 - char format_buffer[FORMAT_BUFFER_LEN]; 65.10 - size_t llen = pointer_delta(eol, cp, sizeof(char)); 65.11 - jio_snprintf(format_buffer, FORMAT_BUFFER_LEN, 65.12 - "%%." SIZE_FORMAT "s", llen); 65.13 - st->print(format_buffer, cp); 65.14 - st->cr(); 65.15 - cp = eol+1; 65.16 - st->print("%5s %-35s += ", "", name); 65.17 + if (cp != NULL) { 65.18 + const char* eol; 65.19 + while ((eol = strchr(cp, '\n')) != NULL) { 65.20 + char format_buffer[FORMAT_BUFFER_LEN]; 65.21 + size_t llen = pointer_delta(eol, cp, sizeof(char)); 65.22 + jio_snprintf(format_buffer, FORMAT_BUFFER_LEN, 65.23 + "%%." SIZE_FORMAT "s", llen); 65.24 + st->print(format_buffer, cp); 65.25 + st->cr(); 65.26 + cp = eol+1; 65.27 + st->print("%5s %-35s += ", "", name); 65.28 + } 65.29 + st->print("%-16s", cp); 65.30 } 65.31 - st->print("%-16s", cp); 65.32 } 65.33 st->print(" %s", kind); 65.34 st->cr(); 65.35 @@ -94,18 +96,21 @@ 65.36 st->print("-XX:%s=" UINTX_FORMAT, name, get_uintx()); 65.37 } else if (is_ccstr()) { 65.38 st->print("-XX:%s=", name); 65.39 - // Need to turn embedded '\n's back into separate arguments 65.40 - // Not so efficient to print one character at a time, 65.41 - // but the choice is to do the transformation to a buffer 65.42 - // and print that. And this need not be efficient. 65.43 - for (const char* cp = get_ccstr(); *cp != '\0'; cp += 1) { 65.44 - switch (*cp) { 65.45 - default: 65.46 - st->print("%c", *cp); 65.47 - break; 65.48 - case '\n': 65.49 - st->print(" -XX:%s=", name); 65.50 - break; 65.51 + const char* cp = get_ccstr(); 65.52 + if (cp != NULL) { 65.53 + // Need to turn embedded '\n's back into separate arguments 65.54 + // Not so efficient to print one character at a time, 65.55 + // but the choice is to do the transformation to a buffer 65.56 + // and print that. And this need not be efficient. 65.57 + for (; *cp != '\0'; cp += 1) { 65.58 + switch (*cp) { 65.59 + default: 65.60 + st->print("%c", *cp); 65.61 + break; 65.62 + case '\n': 65.63 + st->print(" -XX:%s=", name); 65.64 + break; 65.65 + } 65.66 } 65.67 } 65.68 } else {
66.1 --- a/src/share/vm/runtime/globals.hpp Thu Apr 10 15:49:16 2008 -0400 66.2 +++ b/src/share/vm/runtime/globals.hpp Fri Apr 11 09:56:35 2008 -0400 66.3 @@ -668,16 +668,19 @@ 66.4 notproduct(bool, PrintCompilation2, false, \ 66.5 "Print additional statistics per compilation") \ 66.6 \ 66.7 - notproduct(bool, PrintAdapterHandlers, false, \ 66.8 + diagnostic(bool, PrintAdapterHandlers, false, \ 66.9 "Print code generated for i2c/c2i adapters") \ 66.10 \ 66.11 - develop(bool, PrintAssembly, false, \ 66.12 - "Print assembly code") \ 66.13 - \ 66.14 - develop(bool, PrintNMethods, false, \ 66.15 + diagnostic(bool, PrintAssembly, false, \ 66.16 + "Print assembly code (using external disassembler.so)") \ 66.17 + \ 66.18 + diagnostic(ccstr, PrintAssemblyOptions, false, \ 66.19 + "Options string passed to disassembler.so") \ 66.20 + \ 66.21 + diagnostic(bool, PrintNMethods, false, \ 66.22 "Print assembly code for nmethods when generated") \ 66.23 \ 66.24 - develop(bool, PrintNativeNMethods, false, \ 66.25 + diagnostic(bool, PrintNativeNMethods, false, \ 66.26 "Print assembly code for native nmethods when generated") \ 66.27 \ 66.28 develop(bool, PrintDebugInfo, false, \ 66.29 @@ -702,7 +705,7 @@ 66.30 develop(bool, PrintCodeCache2, false, \ 66.31 "Print detailed info on the compiled_code cache when exiting") \ 66.32 \ 66.33 - develop(bool, PrintStubCode, false, \ 66.34 + diagnostic(bool, PrintStubCode, false, \ 66.35 "Print generated stub code") \ 66.36 \ 66.37 product(bool, StackTraceInThrowable, true, \ 66.38 @@ -1319,6 +1322,10 @@ 66.39 product(bool, CMSClassUnloadingEnabled, false, \ 66.40 "Whether class unloading enabled when using CMS GC") \ 66.41 \ 66.42 + product(uintx, CMSClassUnloadingMaxInterval, 0, \ 66.43 + "When CMS class unloading is enabled, the maximum CMS cycle count"\ 66.44 + " for which classes may not be unloaded") \ 66.45 + \ 66.46 product(bool, CMSCompactWhenClearAllSoftRefs, true, \ 66.47 "Compact when asked to collect CMS gen with clear_all_soft_refs") \ 66.48 \ 66.49 @@ -1504,17 +1511,30 @@ 66.50 "Percentage of MinHeapFreeRatio in CMS generation that is " \ 66.51 " allocated before a CMS collection cycle commences") \ 66.52 \ 66.53 - product(intx, CMSBootstrapOccupancy, 50, \ 66.54 + product(intx, CMSTriggerPermRatio, 80, \ 66.55 + "Percentage of MinHeapFreeRatio in the CMS perm generation that" \ 66.56 + " is allocated before a CMS collection cycle commences, that " \ 66.57 + " also collects the perm generation") \ 66.58 + \ 66.59 + product(uintx, CMSBootstrapOccupancy, 50, \ 66.60 "Percentage CMS generation occupancy at which to " \ 66.61 " initiate CMS collection for bootstrapping collection stats") \ 66.62 \ 66.63 product(intx, CMSInitiatingOccupancyFraction, -1, \ 66.64 "Percentage CMS generation occupancy to start a CMS collection " \ 66.65 - " cycle (A negative value means that CMSTirggerRatio is used)") \ 66.66 + " cycle (A negative value means that CMSTriggerRatio is used)") \ 66.67 + \ 66.68 + product(intx, CMSInitiatingPermOccupancyFraction, -1, \ 66.69 + "Percentage CMS perm generation occupancy to start a CMScollection"\ 66.70 + " cycle (A negative value means that CMSTriggerPermRatio is used)")\ 66.71 \ 66.72 product(bool, UseCMSInitiatingOccupancyOnly, false, \ 66.73 "Only use occupancy as a crierion for starting a CMS collection") \ 66.74 \ 66.75 + product(intx, CMSIsTooFullPercentage, 98, \ 66.76 + "An absolute ceiling above which CMS will always consider the" \ 66.77 + " perm gen ripe for collection") \ 66.78 + \ 66.79 develop(bool, CMSTestInFreeList, false, \ 66.80 "Check if the coalesced range is already in the " \ 66.81 "free lists as claimed.") \ 66.82 @@ -2250,7 +2270,7 @@ 66.83 product_pd(bool, RewriteFrequentPairs, \ 66.84 "Rewrite frequently used bytecode pairs into a single bytecode") \ 66.85 \ 66.86 - product(bool, PrintInterpreter, false, \ 66.87 + diagnostic(bool, PrintInterpreter, false, \ 66.88 "Prints the generated interpreter code") \ 66.89 \ 66.90 product(bool, UseInterpreter, true, \ 66.91 @@ -2300,7 +2320,7 @@ 66.92 develop(bool, PrintBytecodePairHistogram, false, \ 66.93 "Print histogram of the executed bytecode pairs") \ 66.94 \ 66.95 - develop(bool, PrintSignatureHandlers, false, \ 66.96 + diagnostic(bool, PrintSignatureHandlers, false, \ 66.97 "Print code generated for native method signature handlers") \ 66.98 \ 66.99 develop(bool, VerifyOops, false, \
67.1 --- a/src/share/vm/runtime/stubCodeGenerator.cpp Thu Apr 10 15:49:16 2008 -0400 67.2 +++ b/src/share/vm/runtime/stubCodeGenerator.cpp Fri Apr 11 09:56:35 2008 -0400 67.3 @@ -69,7 +69,6 @@ 67.4 _first_stub = _last_stub = NULL; 67.5 } 67.6 67.7 -#ifndef PRODUCT 67.8 extern "C" { 67.9 static int compare_cdesc(const void* void_a, const void* void_b) { 67.10 int ai = (*((StubCodeDesc**) void_a))->index(); 67.11 @@ -77,10 +76,8 @@ 67.12 return ai - bi; 67.13 } 67.14 } 67.15 -#endif 67.16 67.17 StubCodeGenerator::~StubCodeGenerator() { 67.18 -#ifndef PRODUCT 67.19 if (PrintStubCode) { 67.20 CodeBuffer* cbuf = _masm->code(); 67.21 CodeBlob* blob = CodeCache::find_blob_unsafe(cbuf->insts()->start()); 67.22 @@ -105,7 +102,6 @@ 67.23 tty->cr(); 67.24 } 67.25 } 67.26 -#endif //PRODUCT 67.27 } 67.28 67.29
68.1 --- a/src/share/vm/runtime/vframe.hpp Thu Apr 10 15:49:16 2008 -0400 68.2 +++ b/src/share/vm/runtime/vframe.hpp Fri Apr 11 09:56:35 2008 -0400 68.3 @@ -416,6 +416,48 @@ 68.4 int decode_offset; 68.5 if (pc_desc == NULL) { 68.6 // Should not happen, but let fill_from_compiled_frame handle it. 68.7 + 68.8 + // If we are trying to walk the stack of a thread that is not 68.9 + // at a safepoint (like AsyncGetCallTrace would do) then this is an 68.10 + // acceptable result. [ This is assuming that safe_for_sender 68.11 + // is so bullet proof that we can trust the frames it produced. ] 68.12 + // 68.13 + // So if we see that the thread is not safepoint safe 68.14 + // then simply produce the method and a bci of zero 68.15 + // and skip the possibility of decoding any inlining that 68.16 + // may be present. That is far better than simply stopping (or 68.17 + // asserting. If however the thread is safepoint safe this 68.18 + // is the sign of a compiler bug and we'll let 68.19 + // fill_from_compiled_frame handle it. 68.20 + 68.21 + 68.22 + JavaThreadState state = _thread->thread_state(); 68.23 + 68.24 + // in_Java should be good enough to test safepoint safety 68.25 + // if state were say in_Java_trans then we'd expect that 68.26 + // the pc would have already been slightly adjusted to 68.27 + // one that would produce a pcDesc since the trans state 68.28 + // would be one that might in fact anticipate a safepoint 68.29 + 68.30 + if (state == _thread_in_Java ) { 68.31 + // This will get a method a zero bci and no inlining. 68.32 + // Might be nice to have a unique bci to signify this 68.33 + // particular case but for now zero will do. 68.34 + 68.35 + fill_from_compiled_native_frame(); 68.36 + 68.37 + // There is something to be said for setting the mode to 68.38 + // at_end_mode to prevent trying to walk further up the 68.39 + // stack. There is evidence that if we walk any further 68.40 + // that we could produce a bad stack chain. However until 68.41 + // we see evidence that allowing this causes us to find 68.42 + // frames bad enough to cause segv's or assertion failures 68.43 + // we don't do it as while we may get a bad call chain the 68.44 + // probability is much higher (several magnitudes) that we 68.45 + // get good data. 68.46 + 68.47 + return true; 68.48 + } 68.49 decode_offset = DebugInformationRecorder::serialized_null; 68.50 } else { 68.51 decode_offset = pc_desc->scope_decode_offset();
69.1 --- a/src/share/vm/utilities/ostream.cpp Thu Apr 10 15:49:16 2008 -0400 69.2 +++ b/src/share/vm/utilities/ostream.cpp Fri Apr 11 09:56:35 2008 -0400 69.3 @@ -52,8 +52,9 @@ 69.4 _precount += _position + 1; 69.5 _position = 0; 69.6 } else if (ch == '\t') { 69.7 - _position += 8; 69.8 - _precount -= 7; // invariant: _precount + _position == total count 69.9 + int tw = 8 - (_position & 7); 69.10 + _position += tw; 69.11 + _precount -= tw-1; // invariant: _precount + _position == total count 69.12 } else { 69.13 _position += 1; 69.14 } 69.15 @@ -133,7 +134,17 @@ 69.16 } 69.17 69.18 void outputStream::fill_to(int col) { 69.19 - while (position() < col) sp(); 69.20 + int need_fill = col - position(); 69.21 + sp(need_fill); 69.22 +} 69.23 + 69.24 +void outputStream::move_to(int col, int slop, int min_space) { 69.25 + if (position() >= col + slop) 69.26 + cr(); 69.27 + int need_fill = col - position(); 69.28 + if (need_fill < min_space) 69.29 + need_fill = min_space; 69.30 + sp(need_fill); 69.31 } 69.32 69.33 void outputStream::put(char ch) { 69.34 @@ -142,8 +153,23 @@ 69.35 write(buf, 1); 69.36 } 69.37 69.38 -void outputStream::sp() { 69.39 - this->write(" ", 1); 69.40 +#define SP_USE_TABS false 69.41 + 69.42 +void outputStream::sp(int count) { 69.43 + if (count < 0) return; 69.44 + if (SP_USE_TABS && count >= 8) { 69.45 + int target = position() + count; 69.46 + while (count >= 8) { 69.47 + this->write("\t", 1); 69.48 + count -= 8; 69.49 + } 69.50 + count = target - position(); 69.51 + } 69.52 + while (count > 0) { 69.53 + int nw = (count > 8) ? 8 : count; 69.54 + this->write(" ", nw); 69.55 + count -= nw; 69.56 + } 69.57 } 69.58 69.59 void outputStream::cr() {
70.1 --- a/src/share/vm/utilities/ostream.hpp Thu Apr 10 15:49:16 2008 -0400 70.2 +++ b/src/share/vm/utilities/ostream.hpp Fri Apr 11 09:56:35 2008 -0400 70.3 @@ -59,6 +59,7 @@ 70.4 int indentation() const { return _indentation; } 70.5 void set_indentation(int i) { _indentation = i; } 70.6 void fill_to(int col); 70.7 + void move_to(int col, int slop = 6, int min_space = 2); 70.8 70.9 // sizing 70.10 int width() const { return _width; } 70.11 @@ -78,7 +79,7 @@ 70.12 void print_raw_cr(const char* str) { write(str, strlen(str)); cr(); } 70.13 void print_raw_cr(const char* str, int len){ write(str, len); cr(); } 70.14 void put(char ch); 70.15 - void sp(); 70.16 + void sp(int count = 1); 70.17 void cr(); 70.18 void bol() { if (_position > 0) cr(); } 70.19
71.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 71.2 +++ b/test/compiler/6646020/Tester.java Fri Apr 11 09:56:35 2008 -0400 71.3 @@ -0,0 +1,886 @@ 71.4 +/* 71.5 + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. 71.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 71.7 + * 71.8 + * This code is free software; you can redistribute it and/or modify it 71.9 + * under the terms of the GNU General Public License version 2 only, as 71.10 + * published by the Free Software Foundation. 71.11 + * 71.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 71.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 71.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 71.15 + * version 2 for more details (a copy is included in the LICENSE file that 71.16 + * accompanied this code). 71.17 + * 71.18 + * You should have received a copy of the GNU General Public License version 71.19 + * 2 along with this work; if not, write to the Free Software Foundation, 71.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 71.21 + * 71.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 71.23 + * CA 95054 USA or visit www.sun.com if you need additional information or 71.24 + * have any questions. 71.25 + */ 71.26 + 71.27 +/* 71.28 + * @test 71.29 + * @bug 6646020 71.30 + * @summary assert(in_bb(n),"must be in block") in -Xcomp mode 71.31 + */ 71.32 + 71.33 +/* Complexity upper bound: 3361 ops */ 71.34 + 71.35 +class Tester_Class_0 { 71.36 + static byte var_1; 71.37 + 71.38 + 71.39 + public Tester_Class_0() 71.40 + { 71.41 + "".length(); 71.42 + { 71.43 + var_1 = (var_1 = (new byte[(byte)'D'])[(byte)2.40457E38F]); 71.44 + var_1 = (var_1 = (byte)1.738443503665377E307); 71.45 + var_1 = (var_1 = (byte)1237144669662298112L); 71.46 + } 71.47 + var_1 = "baldh".equalsIgnoreCase("") ? (var_1 = (byte)7.2932087E37F) : (byte)3909726578709910528L; 71.48 + var_1 = (var_1 = (var_1 = (var_1 = (byte)7.223761846153971E307))); 71.49 + var_1 = (var_1 = (var_1 = (var_1 = (var_1 = (byte)((short)7860452029249754112L + (byte)1.7374232546809952E308))))); 71.50 + var_1 = (!true ? (var_1 = (byte)4359229782598970368L) : (short)(byte)1.7509836746850026E308) >= 'P' ? (var_1 = (byte)3.275114793095594E307) : (byte)(- ((byte)1.5595572E38F) / 8.2971296E37F); 71.51 + byte var_9 = (true ? true : (false ? true : false)) ? (var_1 = (var_1 = (byte)9.928434E37F)) : (var_1 = (byte)9.785060633966518E307); 71.52 + final byte var_10 = 53; 71.53 + var_9 <<= (true | true) & (((var_10 == "".substring(2001075014).compareToIgnoreCase("rhbytggv") ? !true : ! !true) ? !false : false) ? !true & true : !false) ? var_10 : var_10; 71.54 + var_9 <<= - (var_9 -= - ~6397182310329038848L >> (char)955837891 << (short)- - -8.4452034E37F >> + ~5485157895941338112L); 71.55 + --var_9; 71.56 + var_9 >>= 'V'; 71.57 + var_9 -= (new char[var_10])[var_9]; 71.58 + double var_11; 71.59 + var_11 = (var_11 = (new int[var_9 = (var_9 %= 684423748)])[var_9]); 71.60 + var_9 /= 'q'; 71.61 + var_9 *= ~var_9 | (short)1.7667766368850557E308 - "w".trim().charAt(- (var_9 /= + (var_11 = 'q'))); 71.62 + if (var_10 <= 605036859609030656L | !false & false) 71.63 + { 71.64 + var_9 >>>= false ^ false ? (new short[var_10])[var_10] : (short)1013619326108001280L; 71.65 + } 71.66 + else 71.67 + { 71.68 + var_11 = var_9; 71.69 + } 71.70 + var_9 -= 'X'; 71.71 + var_9 *= 'E'; 71.72 + { 71.73 + var_9 ^= (new short[var_9])[var_9 >>>= 'c']; 71.74 + } 71.75 + var_11 = 4315867074042433536L; 71.76 + double var_12 = 1.2183900219527627E308; 71.77 + var_9 <<= (false ? !false : false) ? '\\' : 'D'; 71.78 + } 71.79 + 71.80 + 71.81 + 71.82 + 71.83 + private final long func_0() 71.84 + { 71.85 + float var_2 = 0F; 71.86 + var_1 = (var_1 = (var_1 = (byte)((short)1.4106931056021857E308 % var_2))); 71.87 + for (new String(); true & (! !true ^ !false | false) && var_2 < 1; var_1 = (var_1 = (var_1 = (var_1 = (byte)1183673628639185920L)))) 71.88 + { 71.89 + var_1 = true | false ? (var_1 = (byte)1.6263855E37F) : (byte)'O'; 71.90 + var_2++; 71.91 + "fui".toUpperCase(); 71.92 + final int var_3 = (var_1 = (var_1 = (byte)'i')) + (byte)2008561384 / (byte)1.4413369179905006E308; 71.93 + } 71.94 + var_1 = (var_1 = false ^ false ? (byte)2.3850814E38F : (byte)4.42887E37F); 71.95 + final float var_4 = 3.052265E38F; 71.96 + var_1 = (var_1 = (var_1 = (var_1 = (var_1 = (byte)'o')))); 71.97 + long var_5; 71.98 + var_1 = (var_1 = (byte)((var_1 = (byte)1913212786) * (var_1 = (byte)var_2))); 71.99 + var_5 = (short)3.2024069E38F * (short)(var_5 = 'Q'); 71.100 + var_5 = (false ? true : false) ? (short)1098137179 : (byte)~695765814858203136L; 71.101 + var_1 = (var_1 = true & false ^ true ? (byte)1662737306 : (byte)'r'); 71.102 + { 71.103 + (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]); 71.104 + } 71.105 + double var_6; 71.106 + var_6 = 1359078277; 71.107 + final float var_7 = 3.5952457E37F; 71.108 + var_5 = ('u' | 9005660398910009344L) << 'j'; 71.109 + int var_8; 71.110 + var_5 = (!false || true & !false) && false ? (byte)1836342254 : (byte)1.4836203E38F; 71.111 + var_1 = (var_1 = (var_1 = (var_1 = (byte)1.5824984701060493E308))); 71.112 + var_1 = (var_1 = (var_1 = (byte)~ (var_1 = (var_1 = (var_1 = (byte)var_7))))); 71.113 + 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); 71.114 + } 71.115 + 71.116 + protected final static double func_1(final char arg_0, final long arg_1) 71.117 + { 71.118 + var_1 = (short)8779631802405542912L << 'x' <= arg_0 ? (byte)+9.96859509852443E307 : (var_1 = (var_1 = (byte)(short)5.218454879223281E307)); 71.119 + return 5.57437404144192E307; 71.120 + } 71.121 + 71.122 + double func_2(byte arg_0, final boolean arg_1, Object arg_2) 71.123 + { 71.124 + arg_2 = arg_1 != arg_1 ? "wq" : "w"; 71.125 + arg_2 = arg_2; 71.126 + if (arg_1) 71.127 + { 71.128 + arg_2 = false & arg_1 ? "hasmp" : (arg_2 = arg_2); 71.129 + } 71.130 + else 71.131 + { 71.132 + arg_2 = "lcquv"; 71.133 + } 71.134 + arg_0 -= arg_1 ^ false ? (arg_0 |= (short)arg_0) : (~3462197988186869760L | 7274210797196514304L) % - - + +130998764279904256L; 71.135 + arg_0 &= (true ? - - ~7861994999369861120L << 'l' : 'c') * 1246069704; 71.136 + return (arg_1 ? 9.311174E37F : 1.7085558737202237E308) * 1168887722; 71.137 + } 71.138 + 71.139 + public String toString() 71.140 + { 71.141 + String result = "[\n"; 71.142 + result += "Tester_Class_0.var_1 = "; result += Tester.Printer.print(var_1); 71.143 + result += ""; 71.144 + result += "\n]"; 71.145 + return result; 71.146 + } 71.147 +} 71.148 + 71.149 + 71.150 +final class Tester_Class_1 extends Tester_Class_0 { 71.151 + static Object var_13; 71.152 + final static boolean var_14 = false | (false ? false : true); 71.153 + Object var_15; 71.154 + static byte var_16; 71.155 + final long var_17 = (long)(-9.40561658911133E307 - (short)2.2016736E38F) ^ (char)1099667310; 71.156 + static boolean var_18; 71.157 + static float var_19; 71.158 + final static byte var_20 = 123; 71.159 + static byte var_21 = var_1 = (var_1 = var_20); 71.160 + final static float var_22 = 1.5415572E38F; 71.161 + 71.162 + 71.163 + public Tester_Class_1() 71.164 + { 71.165 + char[][] var_39; 71.166 + boolean var_40 = false | !var_14; 71.167 + if (var_14) 71.168 + { 71.169 + final String[] var_41 = (new String[var_21][var_20])[var_21 *= var_21]; 71.170 + var_15 = (new Tester_Class_0[var_20])[var_20]; 71.171 + --var_21; 71.172 + int var_42; 71.173 + } 71.174 + else 71.175 + { 71.176 + var_19 = (short)325110146; 71.177 + } 71.178 + var_40 &= true; 71.179 + 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]); 71.180 + var_15 = "m"; 71.181 + } 71.182 + 71.183 + 71.184 + 71.185 + 71.186 + 71.187 + protected final static Tester_Class_0 func_0(final char arg_0, boolean arg_1) 71.188 + { 71.189 + final short var_23 = false ? (short)2.2956268E38F : var_20; 71.190 + { 71.191 + ((new Tester_Class_1[var_21])[var_20]).var_15 = ((new Tester_Class_0[var_20][var_21])[var_21])[var_20]; 71.192 + } 71.193 + var_19 = var_23; 71.194 + { 71.195 + var_21++; 71.196 + --var_21; 71.197 + var_13 = (false ? arg_1 : arg_1) ? "" : "aianteahl"; 71.198 + arg_1 ^= ! (var_14 ? var_14 : !var_14); 71.199 + } 71.200 + (arg_1 ? "rq" : "certd").trim(); 71.201 + arg_1 ^= 's' < var_22; 71.202 + var_19 = 'T'; 71.203 + var_19 = var_14 ? --var_21 : var_20; 71.204 + var_19 = (var_21 >>>= ~ -1559436447128426496L >> 88912720393932800L) | (new char[var_20][var_21])[var_21][var_20]; 71.205 + short var_24 = 7601; 71.206 + if (arg_1) 71.207 + { 71.208 + var_13 = (new Tester_Class_0[var_20])[var_21]; 71.209 + } 71.210 + else 71.211 + { 71.212 + var_19 = var_23; 71.213 + } 71.214 + var_19 = var_24; 71.215 + var_19 = 174274929356416000L; 71.216 + return arg_1 ? (Tester_Class_0)(new Object[var_20])[var_21 >>>= - ((byte)6471979169965446144L)] : (new Tester_Class_0[var_21])[var_20]; 71.217 + } 71.218 + 71.219 + private static int func_1(final Object arg_0, final boolean arg_1) 71.220 + { 71.221 + var_19 = 'N'; 71.222 + var_13 = "ftspm".toUpperCase(); 71.223 + var_18 = arg_1 ? !arg_1 : var_14; 71.224 + var_19 = var_21 % 'j'; 71.225 + { 71.226 + var_13 = new short[var_21 >>= 8019540572802872320L]; 71.227 + } 71.228 + 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); 71.229 + "cltpxrg".offsetByCodePoints((new short[var_20])[(byte)'F'] & var_20, 942627356); 71.230 + final Object var_26 = ((new Tester_Class_1[var_21])[var_20]).var_15 = arg_0; 71.231 + { 71.232 + var_21 |= 'H'; 71.233 + } 71.234 + var_19 = 4705089801895780352L; 71.235 + var_19 = (var_18 = arg_1 & false) ? var_20 : (! (~var_21 > var_22) ? (new short[var_20])[var_21] : (short)3904907750551380992L); 71.236 + var_18 = false; 71.237 + { 71.238 + var_18 = "aoy".startsWith("ia", 18060804); 71.239 + if (true) 71.240 + { 71.241 + final short var_27 = 4832; 71.242 + } 71.243 + else 71.244 + { 71.245 + var_18 = (var_18 = arg_1) ? !false : !var_14; 71.246 + } 71.247 + var_18 = (var_18 = var_14); 71.248 + var_19 = 'L'; 71.249 + } 71.250 + 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); 71.251 + double var_28 = 0; 71.252 + var_21 %= -var_28; 71.253 + for (byte var_29 = 91; arg_1 && (var_28 < 1 && false); var_19 = var_20) 71.254 + { 71.255 + var_19 = (var_18 = arg_1) & (var_18 = false) ? 'm' : '['; 71.256 + var_28++; 71.257 + var_18 = var_14; 71.258 + var_21 += (short)1363703973; 71.259 + } 71.260 + var_19 = (var_19 = var_22); 71.261 + var_18 = (var_18 = false | false ? 1743087391 <= (var_21 >>= 8790741242417599488L) : !arg_1); 71.262 + var_18 = true | true; 71.263 + --var_21; 71.264 + var_18 = !var_14 & false; 71.265 + "mt".indexOf(var_14 ? new String("fpu") : "awivb", (var_14 ? !true : (var_18 = var_14)) ? + ++var_21 : ~var_20); 71.266 + return (short)(new float[var_21--])[var_21] & ((var_18 = false) ? (var_21 *= 'N') : var_20 + (short)1680927063794178048L) & 1839004800; 71.267 + } 71.268 + 71.269 + protected static int func_2(Tester_Class_0[][] arg_0) 71.270 + { 71.271 + ((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]; 71.272 + ((new Tester_Class_1[var_20])[var_20]).var_15 = "d"; 71.273 + int var_30 = 0; 71.274 + "joxjgpywp".lastIndexOf(1834367264 >> var_21, (byte)7.572305E37F >>> (false ? (short)2.3909862E38F : + - +3939434849912855552L)); 71.275 + while (var_14 | false ^ var_14 && (var_30 < 1 && true)) 71.276 + { 71.277 + var_1 = var_20; 71.278 + var_30++; 71.279 + var_13 = new float[var_21][--var_21]; 71.280 + boolean var_31; 71.281 + } 71.282 + var_19 = ((new Tester_Class_1[var_21])[var_20]).var_17 <= (~2158227803735181312L & 6001748808824762368L) ? (short)var_20 : var_20; 71.283 + var_18 = (var_18 = true); 71.284 + return (byte)(new short[var_20])[var_20] >>> ((new char[var_21][var_21])[var_21 |= 6074708801143703552L])[var_20]; 71.285 + } 71.286 + 71.287 + private final String func_3(boolean arg_0, short arg_1, short arg_2) 71.288 + { 71.289 + var_13 = (Tester_Class_0)((arg_0 ^= arg_0) ? (var_13 = (var_15 = (var_15 = "grfphyrs"))) : (var_13 = new Object[var_21 *= ']'])); 71.290 + if (true & ! (arg_0 ^= !arg_0 | true)) 71.291 + { 71.292 + boolean var_32 = true; 71.293 + var_19 = --arg_1; 71.294 + arg_2 <<= var_21; 71.295 + } 71.296 + else 71.297 + { 71.298 + arg_0 |= false; 71.299 + } 71.300 + var_21 >>>= arg_1; 71.301 + final float var_33 = 2.5500976E38F; 71.302 + return ""; 71.303 + } 71.304 + 71.305 + private static String func_4(final double arg_0, final Object arg_1, final short[] arg_2, final char arg_3) 71.306 + { 71.307 + float var_34; 71.308 + var_21++; 71.309 + ((new Tester_Class_1[var_20])[var_20]).var_15 = false ? arg_1 : arg_1; 71.310 + var_13 = arg_1; 71.311 + var_19 = var_22; 71.312 + var_13 = new long[var_21 /= 1038797776 + var_21][--var_21]; 71.313 + ++var_21; 71.314 + var_18 = false && false; 71.315 + var_21--; 71.316 + "".lastIndexOf("kjro"); 71.317 + final int var_35 = (var_21 <<= var_21--) * var_21--; 71.318 + if ("kohilkx".startsWith("gy", var_35)) 71.319 + { 71.320 + var_34 = 2.0849673E37F; 71.321 + } 71.322 + else 71.323 + { 71.324 + double var_36 = arg_0; 71.325 + } 71.326 + var_34 = (var_21 /= var_20); 71.327 + { 71.328 + func_2(new Tester_Class_0[var_20][var_21]); 71.329 + var_34 = var_20 * (- ~5805881602002385920L / arg_3) << (short)~8041668398152312832L; 71.330 + var_13 = (var_13 = "qfwbfdf"); 71.331 + } 71.332 + ((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); 71.333 + var_18 = (var_18 = var_14) & var_14; 71.334 + if ((new boolean[var_21])[var_21 >>= 121380821]) 71.335 + { 71.336 + var_34 = 1382979413; 71.337 + } 71.338 + else 71.339 + { 71.340 + var_34 = (var_20 & var_20) + (true ? 'I' : arg_3); 71.341 + } 71.342 + byte var_37; 71.343 + ((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; 71.344 + byte var_38 = 1; 71.345 + var_38 -= arg_0; 71.346 + var_34 = arg_3; 71.347 + return var_14 ? "" : "xgkr".toUpperCase(); 71.348 + } 71.349 + 71.350 + public String toString() 71.351 + { 71.352 + String result = "[\n"; 71.353 + result += "Tester_Class_1.var_1 = "; result += Tester.Printer.print(var_1); 71.354 + result += "\n"; 71.355 + result += "Tester_Class_1.var_16 = "; result += Tester.Printer.print(var_16); 71.356 + result += "\n"; 71.357 + result += "Tester_Class_1.var_20 = "; result += Tester.Printer.print(var_20); 71.358 + result += "\n"; 71.359 + result += "Tester_Class_1.var_21 = "; result += Tester.Printer.print(var_21); 71.360 + result += "\n"; 71.361 + result += "Tester_Class_1.var_14 = "; result += Tester.Printer.print(var_14); 71.362 + result += "\n"; 71.363 + result += "Tester_Class_1.var_18 = "; result += Tester.Printer.print(var_18); 71.364 + result += "\n"; 71.365 + result += "Tester_Class_1.var_17 = "; result += Tester.Printer.print(var_17); 71.366 + result += "\n"; 71.367 + result += "Tester_Class_1.var_19 = "; result += Tester.Printer.print(var_19); 71.368 + result += "\n"; 71.369 + result += "Tester_Class_1.var_22 = "; result += Tester.Printer.print(var_22); 71.370 + result += "\n"; 71.371 + result += "Tester_Class_1.var_13 = "; result += Tester.Printer.print(var_13); 71.372 + result += "\n"; 71.373 + result += "Tester_Class_1.var_15 = "; result += Tester.Printer.print(var_15); 71.374 + result += ""; 71.375 + result += "\n]"; 71.376 + return result; 71.377 + } 71.378 +} 71.379 + 71.380 + 71.381 +class Tester_Class_2 extends Tester_Class_0 { 71.382 + final int var_43 = 1600723343; 71.383 + static long var_44 = ~1297640037857117184L; 71.384 + static String var_45 = "ejaglds"; 71.385 + double var_46; 71.386 + static float var_47 = 7.9423827E37F; 71.387 + static Tester_Class_1[][] var_48; 71.388 + 71.389 + 71.390 + public Tester_Class_2() 71.391 + { 71.392 + var_45 = (var_45 = "nkulkweqt"); 71.393 + var_47 %= (new char[Tester_Class_1.var_21 >>= (short)Tester_Class_1.var_20])[Tester_Class_1.var_20]; 71.394 + { 71.395 + Tester_Class_1.var_18 = Tester_Class_1.var_14; 71.396 + } 71.397 + var_47 %= 1.559461406041646E308; 71.398 + var_44 -= Tester_Class_1.var_21++ & ((new Tester_Class_1[Tester_Class_1.var_20])[Tester_Class_1.var_20]).var_17; 71.399 + var_44 *= false ? (short)Tester_Class_1.var_20 : (short)var_47; 71.400 + Tester_Class_1.var_13 = (new Tester_Class_1().var_15 = new char[Tester_Class_1.var_20]); 71.401 + var_46 = 'i'; 71.402 + double var_49 = var_46 = false ? (var_47 *= (var_46 = var_43)) : Tester_Class_1.var_20; 71.403 + var_49 += 'k'; 71.404 + } 71.405 + 71.406 + 71.407 + 71.408 + 71.409 + public String toString() 71.410 + { 71.411 + String result = "[\n"; 71.412 + result += "Tester_Class_2.var_43 = "; result += Tester.Printer.print(var_43); 71.413 + result += "\n"; 71.414 + result += "Tester_Class_2.var_48 = "; result += Tester.Printer.print(var_48); 71.415 + result += "\n"; 71.416 + result += "Tester_Class_2.var_44 = "; result += Tester.Printer.print(var_44); 71.417 + result += "\n"; 71.418 + result += "Tester_Class_2.var_46 = "; result += Tester.Printer.print(var_46); 71.419 + result += "\n"; 71.420 + result += "Tester_Class_2.var_47 = "; result += Tester.Printer.print(var_47); 71.421 + result += "\n"; 71.422 + result += "Tester_Class_2.var_1 = "; result += Tester.Printer.print(var_1); 71.423 + result += "\n"; 71.424 + result += "Tester_Class_2.var_45 = "; result += Tester.Printer.print(var_45); 71.425 + result += ""; 71.426 + result += "\n]"; 71.427 + return result; 71.428 + } 71.429 +} 71.430 + 71.431 + 71.432 +class Tester_Class_3 extends Tester_Class_0 { 71.433 + byte var_50; 71.434 + int var_51; 71.435 + static double var_52; 71.436 + static boolean var_53 = true; 71.437 + long var_54; 71.438 + static short var_55; 71.439 + short var_56; 71.440 + 71.441 + 71.442 + public Tester_Class_3() 71.443 + { 71.444 + var_53 |= false; 71.445 + (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"); 71.446 + Tester_Class_2.var_45 = Tester_Class_2.var_45; 71.447 + double var_68 = 0; 71.448 + Tester_Class_1.var_19 = (var_55 = Tester_Class_1.var_20); 71.449 + do 71.450 + { 71.451 + var_53 ^= 'T' > Tester_Class_1.var_21-- & (var_53 |= Tester_Class_1.var_14); 71.452 + Tester_Class_2.var_44 >>= (char)3.928497616986412E307; 71.453 + var_68++; 71.454 + 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)); 71.455 + } while ((((var_56 = (short)1161292485) != 'M' ? var_53 : Tester_Class_1.var_14) ? Tester_Class_1.var_14 ^ true : var_53) && var_68 < 1); 71.456 + Tester_Class_2.var_45 = Tester_Class_2.var_45; 71.457 + ((Tester_Class_1)(Tester_Class_1.var_13 = new Tester_Class_2())).var_15 = Tester_Class_2.var_45; 71.458 + 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)'[')); 71.459 + var_52 = (var_51 = (var_55 = Tester_Class_1.var_20)); 71.460 + double var_69 = 0; 71.461 + 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; 71.462 + do 71.463 + { 71.464 + var_51 = 495861255; 71.465 + var_69++; 71.466 + } while (var_69 < 3); 71.467 + Tester_Class_2.var_47 -= Tester_Class_1.var_20; 71.468 + Tester_Class_2.var_47 %= '['; 71.469 + } 71.470 + 71.471 + 71.472 + 71.473 + 71.474 + static Object func_0(final Tester_Class_0 arg_0, String arg_1, final float arg_2, final long arg_3) 71.475 + { 71.476 + (!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(); 71.477 + 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; 71.478 + return (new Object[Tester_Class_1.var_21])[Tester_Class_1.var_21]; 71.479 + } 71.480 + 71.481 + boolean func_1() 71.482 + { 71.483 + { 71.484 + Tester_Class_1.var_21 >>= (var_56 = (Tester_Class_1.var_21 |= (Tester_Class_1.var_21 -= Tester_Class_1.var_20))); 71.485 + Tester_Class_2.var_45 = "w"; 71.486 + var_51 = Tester_Class_1.var_21; 71.487 + Object var_57; 71.488 + ((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); 71.489 + } 71.490 + Tester_Class_1.var_21 &= (var_55 = (byte)(Tester_Class_1.var_14 ? -Tester_Class_1.var_20 : 4290961666344782848L)); 71.491 + Tester_Class_2.var_45 = Tester_Class_2.var_45; 71.492 + 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; 71.493 + { 71.494 + 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]); 71.495 + Object var_59; 71.496 + Tester_Class_1.var_21 |= 'X'; 71.497 + var_53 ^= Tester_Class_1.var_14; 71.498 + } 71.499 + int var_60 = 0; 71.500 + var_53 |= var_53; 71.501 + 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) 71.502 + { 71.503 + var_51 = var_61; 71.504 + var_60++; 71.505 + var_61 &= (new short[Tester_Class_1.var_20][Tester_Class_1.var_20])[Tester_Class_1.var_20][Tester_Class_1.var_21]; 71.506 + Tester_Class_2.var_45 = "vsuy"; 71.507 + } 71.508 + 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(); 71.509 + var_62 = var_62; 71.510 + float var_63; 71.511 + Object var_64; 71.512 + Tester_Class_2.var_44 <<= 'v'; 71.513 + String var_65; 71.514 + { 71.515 + var_51 = Tester_Class_1.var_21; 71.516 + } 71.517 + var_55 = true ? (var_56 = Tester_Class_1.var_20) : (var_55 = Tester_Class_1.var_20); 71.518 + var_56 = Tester_Class_1.var_21; 71.519 + Tester_Class_1.var_21 |= var_60; 71.520 + Object var_66; 71.521 + Tester_Class_2 var_67; 71.522 + return true & Tester_Class_1.var_14 ^ (false ? var_53 : var_53); 71.523 + } 71.524 + 71.525 + public String toString() 71.526 + { 71.527 + String result = "[\n"; 71.528 + result += "Tester_Class_3.var_51 = "; result += Tester.Printer.print(var_51); 71.529 + result += "\n"; 71.530 + result += "Tester_Class_3.var_54 = "; result += Tester.Printer.print(var_54); 71.531 + result += "\n"; 71.532 + result += "Tester_Class_3.var_52 = "; result += Tester.Printer.print(var_52); 71.533 + result += "\n"; 71.534 + result += "Tester_Class_3.var_55 = "; result += Tester.Printer.print(var_55); 71.535 + result += "\n"; 71.536 + result += "Tester_Class_3.var_56 = "; result += Tester.Printer.print(var_56); 71.537 + result += "\n"; 71.538 + result += "Tester_Class_3.var_1 = "; result += Tester.Printer.print(var_1); 71.539 + result += "\n"; 71.540 + result += "Tester_Class_3.var_50 = "; result += Tester.Printer.print(var_50); 71.541 + result += "\n"; 71.542 + result += "Tester_Class_3.var_53 = "; result += Tester.Printer.print(var_53); 71.543 + result += ""; 71.544 + result += "\n]"; 71.545 + return result; 71.546 + } 71.547 +} 71.548 + 71.549 +public class Tester { 71.550 + final long var_70 = Tester_Class_2.var_44; 71.551 + int var_71; 71.552 + static double var_72; 71.553 + 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); 71.554 + 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)); 71.555 + float var_75; 71.556 + 71.557 + 71.558 + protected final Tester_Class_2 func_0() 71.559 + { 71.560 + Tester_Class_1.var_21 ^= ~Tester_Class_1.var_21; 71.561 + if (false) 71.562 + { 71.563 + ((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)); 71.564 + } 71.565 + else 71.566 + { 71.567 + Tester_Class_2.var_47 += 'H'; 71.568 + } 71.569 + 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]; 71.570 + (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)); 71.571 + var_73 |= ((Tester_Class_2)(Tester_Class_1.var_13 = var_76)).var_43 | Tester_Class_1.var_20; 71.572 + return new Tester_Class_2(); 71.573 + } 71.574 + 71.575 + private static Tester_Class_3 func_1(byte arg_0, Tester_Class_1 arg_1, Tester_Class_1 arg_2, final int arg_3) 71.576 + { 71.577 + arg_0 <<= '`'; 71.578 + 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]; 71.579 + } 71.580 + 71.581 + public static String execute() 71.582 + { 71.583 + try { 71.584 + Tester t = new Tester(); 71.585 + try { t.test(); } 71.586 + catch(Throwable e) { } 71.587 + try { return t.toString(); } 71.588 + catch (Throwable e) { return "Error during result conversion to String"; } 71.589 + } catch (Throwable e) { return "Error during test execution"; } 71.590 + } 71.591 + 71.592 + public static void main(String[] args) 71.593 + { 71.594 + for (int i = 0; i < 20000; i++) { 71.595 + Tester t = new Tester(); 71.596 + try { t.test(); } 71.597 + catch(Throwable e) { } 71.598 + if (t.var_71 != 0 || 71.599 + t.var_70 != -1297640037857117185L || 71.600 + t.var_72 != 0.0 || 71.601 + t.var_75 != 0.0 || 71.602 + t.var_73 != -1 || 71.603 + t.var_74 != 15129) { 71.604 + throw new InternalError("wrong answer"); 71.605 + } 71.606 + } 71.607 + } 71.608 + 71.609 + private void test() 71.610 + { 71.611 + long var_77 = 0L; 71.612 + var_73 /= (Tester_Class_2.var_47 = 'D' | 'Q'); 71.613 + Tester_Class_2.var_47 *= 't'; 71.614 + while (var_77 < 36) 71.615 + { 71.616 + var_73 += Tester_Class_1.var_22; 71.617 + Tester_Class_2.var_47 += Tester_Class_1.var_20; 71.618 + var_77++; 71.619 + Tester_Class_2.var_45 = ""; 71.620 + Tester_Class_2.var_45 = (Tester_Class_2.var_45 = Tester_Class_2.var_45); 71.621 + } 71.622 + if (Tester_Class_3.var_53 |= false) 71.623 + { 71.624 + int var_78 = 0; 71.625 + (false ? "idipdjrln" : "l").startsWith(Tester_Class_2.var_45); 71.626 + 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))) 71.627 + { 71.628 + Tester_Class_2.var_44 <<= 'b'; 71.629 + var_78++; 71.630 + var_72 = var_74; 71.631 + var_71 = (char)6792782617594333184L; 71.632 + } 71.633 + float var_79 = Tester_Class_2.var_47 /= 1.5148047552641134E308; 71.634 + ((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')); 71.635 + 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]; 71.636 + } 71.637 + else 71.638 + { 71.639 + long var_80 = 0L; 71.640 + ((Tester_Class_2)(Tester_Class_1.var_13 = new long[Tester_Class_1.var_21])).var_46 = 'r'; 71.641 + do 71.642 + { 71.643 + final float var_81 = 7.3633934E37F; 71.644 + var_80++; 71.645 + var_73 ^= Tester_Class_2.var_44; 71.646 + } while (Tester_Class_3.var_53 && var_80 < 4); 71.647 + Tester_Class_1.var_18 = Tester_Class_2.var_47 >= var_73; 71.648 + Tester_Class_2.var_45 = "xvodcylp"; 71.649 + 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')); 71.650 + 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]; 71.651 + } 71.652 + var_73 <<= (Tester_Class_1.var_18 = false) ? 't' : (false ? 'E' : 'u'); 71.653 + var_73++; 71.654 + int var_82 = 0; 71.655 + 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); 71.656 + "gdrlrsubb".substring(12438522, var_82); 71.657 + 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' : '['); 71.658 + 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)); 71.659 + Tester_Class_2.var_45 = Tester_Class_2.var_45; 71.660 + while (var_82 < 2 && Tester_Class_3.var_53 & (Tester_Class_3.var_53 ^= !false)) 71.661 + { 71.662 + (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"); 71.663 + var_82++; 71.664 + boolean var_84 = false; 71.665 + Tester_Class_2.var_45 = Tester_Class_2.var_45; 71.666 + } 71.667 + var_71 = ~Tester_Class_2.var_44 != Tester_Class_2.var_44-- ? (var_73 = var_73) : (var_73 >>>= var_73); 71.668 + char var_85; 71.669 + Tester_Class_3.var_53 |= (Tester_Class_3.var_53 ^= true); 71.670 + int var_86 = 0; 71.671 + Tester_Class_1.var_21 %= (var_73 | (Tester_Class_1.var_21 *= 9.831691E37F)) * (Tester_Class_1.var_21 += 6784278051481715712L); 71.672 + 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))) 71.673 + { 71.674 + 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)); 71.675 + var_86++; 71.676 + Tester_Class_2.var_45 = (Tester_Class_2.var_45 = (Tester_Class_2.var_45 = "arceo")); 71.677 + float var_88; 71.678 + } 71.679 + "a".lastIndexOf(var_71 = Tester_Class_3.var_53 ^ false ? (var_71 = 1058420888) : Tester_Class_1.var_20); 71.680 + int var_89 = 0; 71.681 + { 71.682 + var_71 = 661164411; 71.683 + } 71.684 + boolean var_90; 71.685 + --var_73; 71.686 + Tester_Class_2.var_45.concat(Tester_Class_2.var_45); 71.687 + { 71.688 + var_85 = (Tester_Class_3.var_53 ? Tester_Class_3.var_53 : Tester_Class_3.var_53) ? 'R' : '['; 71.689 + } 71.690 + ((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; 71.691 + 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; 71.692 + Tester_Class_2.var_47 *= ((Tester_Class_2)(Tester_Class_0)(Tester_Class_1.var_13 = Tester_Class_2.var_45)).var_43; 71.693 + Tester_Class_2.var_45 = Tester_Class_2.var_45; 71.694 + Tester_Class_3.var_53 &= Tester_Class_1.var_14; 71.695 + while (Tester_Class_1.var_20 >= ++Tester_Class_1.var_21 && var_89 < 2) 71.696 + { 71.697 + Tester_Class_1.var_13 = (Tester_Class_3)(new Tester_Class_0[Tester_Class_1.var_21])[Tester_Class_1.var_21]; 71.698 + var_89++; 71.699 + if (true) 71.700 + { 71.701 + Tester_Class_3.var_53 |= true; 71.702 + break; 71.703 + } 71.704 + else 71.705 + { 71.706 + Tester_Class_2 var_92; 71.707 + } 71.708 + ((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)))); 71.709 + ((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; 71.710 + final char var_93 = 'u'; 71.711 + ((Tester_Class_2)(new Tester_Class_1().var_15 = (Tester_Class_2.var_45 = Tester_Class_2.var_45))).var_46 = var_93; 71.712 + Tester_Class_2.var_45.toUpperCase(); 71.713 + Tester_Class_2.var_45 = "mhk"; 71.714 + (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")))); 71.715 + } 71.716 + float var_94 = 0F; 71.717 + Tester_Class_2.var_44 |= (var_73 >>>= (var_85 = (var_85 = 'j'))); 71.718 + Tester_Class_3.var_52 = 1835242863964218368L; 71.719 + do 71.720 + { 71.721 + int var_95 = 1361237611; 71.722 + var_94++; 71.723 + Tester_Class_3.var_53 ^= (Tester_Class_3.var_53 |= Tester_Class_1.var_14); 71.724 + } while (var_94 < 16); 71.725 + { 71.726 + var_73 = var_73--; 71.727 + Tester_Class_2.var_45 = (Tester_Class_1.var_14 ? Tester_Class_1.var_14 : !false) ? "oaxg" : "igdnja"; 71.728 + } 71.729 + ((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()); 71.730 + byte var_96 = Tester_Class_1.var_21 >>>= (var_85 = (var_85 = '`')); 71.731 + Tester_Class_2.var_45 = ""; 71.732 + Tester_Class_2.var_47 += Tester_Class_2.var_47; 71.733 + Tester_Class_2.var_45 = Tester_Class_2.var_45; 71.734 + } 71.735 + public String toString() 71.736 + { 71.737 + String result = "[\n"; 71.738 + result += "Tester.var_71 = "; result += Printer.print(var_71); 71.739 + result += "\n"; 71.740 + result += "Tester.var_70 = "; result += Printer.print(var_70); 71.741 + result += "\n"; 71.742 + result += "Tester.var_72 = "; result += Printer.print(var_72); 71.743 + result += "\n"; 71.744 + result += "Tester.var_75 = "; result += Printer.print(var_75); 71.745 + result += "\n"; 71.746 + result += "Tester.var_73 = "; result += Printer.print(var_73); 71.747 + result += "\n"; 71.748 + result += "Tester.var_74 = "; result += Printer.print(var_74); 71.749 + result += ""; 71.750 + result += "\n]"; 71.751 + return result; 71.752 + } 71.753 + static class Printer 71.754 + { 71.755 + public static String print(boolean arg) { return String.valueOf(arg); } 71.756 + public static String print(byte arg) { return String.valueOf(arg); } 71.757 + public static String print(short arg) { return String.valueOf(arg); } 71.758 + public static String print(char arg) { return String.valueOf((int)arg); } 71.759 + public static String print(int arg) { return String.valueOf(arg); } 71.760 + public static String print(long arg) { return String.valueOf(arg); } 71.761 + public static String print(float arg) { return String.valueOf(arg); } 71.762 + public static String print(double arg) { return String.valueOf(arg); } 71.763 + 71.764 + 71.765 + public static String print(Object arg) 71.766 + { 71.767 + return print_r(new java.util.Stack(), arg); 71.768 + } 71.769 + 71.770 + private static String print_r(java.util.Stack visitedObjects, Object arg) 71.771 + { 71.772 + String result = ""; 71.773 + if (arg == null) 71.774 + result += "null"; 71.775 + else 71.776 + if (arg.getClass().isArray()) 71.777 + { 71.778 + for (int i = 0; i < visitedObjects.size(); i++) 71.779 + if (visitedObjects.elementAt(i) == arg) return "<recursive>"; 71.780 + 71.781 + visitedObjects.push(arg); 71.782 + 71.783 + final String delimiter = ", "; 71.784 + result += "["; 71.785 + 71.786 + if (arg instanceof Object[]) 71.787 + { 71.788 + Object[] array = (Object[]) arg; 71.789 + for (int i = 0; i < array.length; i++) 71.790 + { 71.791 + result += print_r(visitedObjects, array[i]); 71.792 + if (i < array.length - 1) result += delimiter; 71.793 + } 71.794 + } 71.795 + else 71.796 + if (arg instanceof boolean[]) 71.797 + { 71.798 + boolean[] array = (boolean[]) arg; 71.799 + for (int i = 0; i < array.length; i++) 71.800 + { 71.801 + result += print(array[i]); 71.802 + if (i < array.length - 1) result += delimiter; 71.803 + } 71.804 + } 71.805 + else 71.806 + if (arg instanceof byte[]) 71.807 + { 71.808 + byte[] array = (byte[]) arg; 71.809 + for (int i = 0; i < array.length; i++) 71.810 + { 71.811 + result += print(array[i]); 71.812 + if (i < array.length - 1) result += delimiter; 71.813 + } 71.814 + } 71.815 + else 71.816 + if (arg instanceof short[]) 71.817 + { 71.818 + short[] array = (short[]) arg; 71.819 + for (int i = 0; i < array.length; i++) 71.820 + { 71.821 + result += print(array[i]); 71.822 + if (i < array.length - 1) result += delimiter; 71.823 + } 71.824 + } 71.825 + else 71.826 + if (arg instanceof char[]) 71.827 + { 71.828 + char[] array = (char[]) arg; 71.829 + for (int i = 0; i < array.length; i++) 71.830 + { 71.831 + result += print(array[i]); 71.832 + if (i < array.length - 1) result += delimiter; 71.833 + } 71.834 + } 71.835 + else 71.836 + if (arg instanceof int[]) 71.837 + { 71.838 + int[] array = (int[]) arg; 71.839 + for (int i = 0; i < array.length; i++) 71.840 + { 71.841 + result += print(array[i]); 71.842 + if (i < array.length - 1) result += delimiter; 71.843 + } 71.844 + } 71.845 + else 71.846 + if (arg instanceof long[]) 71.847 + { 71.848 + long[] array = (long[]) arg; 71.849 + for (int i = 0; i < array.length; i++) 71.850 + { 71.851 + result += print(array[i]); 71.852 + if (i < array.length - 1) result += delimiter; 71.853 + } 71.854 + } 71.855 + else 71.856 + if (arg instanceof float[]) 71.857 + { 71.858 + float[] array = (float[]) arg; 71.859 + for (int i = 0; i < array.length; i++) 71.860 + { 71.861 + result += print(array[i]); 71.862 + if (i < array.length - 1) result += delimiter; 71.863 + } 71.864 + } 71.865 + else 71.866 + if (arg instanceof double[]) 71.867 + { 71.868 + double[] array = (double[]) arg; 71.869 + for (int i = 0; i < array.length; i++) 71.870 + { 71.871 + result += print(array[i]); 71.872 + if (i < array.length - 1) result += delimiter; 71.873 + } 71.874 + } 71.875 + 71.876 + result += "]"; 71.877 + visitedObjects.pop(); 71.878 + 71.879 + } else 71.880 + { 71.881 + result += arg.toString(); 71.882 + } 71.883 + 71.884 + return result; 71.885 + } 71.886 + } 71.887 +} 71.888 + 71.889 +