Merge

Fri, 11 Apr 2008 09:56:35 -0400

author
kamg
date
Fri, 11 Apr 2008 09:56:35 -0400
changeset 545
a49a647afe9a
parent 528
c6ff24ceec1c
parent 544
9f4457a14b58
child 548
ba764ed4b6f2

Merge

.hgignore file | annotate | diff | comparison | revisions
make/linux/makefiles/vm.make file | annotate | diff | comparison | revisions
make/linux/platform_amd64 file | annotate | diff | comparison | revisions
make/linux/platform_i486 file | annotate | diff | comparison | revisions
make/linux/platform_sparc file | annotate | diff | comparison | revisions
make/solaris/makefiles/vm.make file | annotate | diff | comparison | revisions
make/solaris/platform_amd64 file | annotate | diff | comparison | revisions
make/solaris/platform_amd64.gcc file | annotate | diff | comparison | revisions
make/solaris/platform_i486 file | annotate | diff | comparison | revisions
make/solaris/platform_i486.gcc file | annotate | diff | comparison | revisions
make/solaris/platform_sparc file | annotate | diff | comparison | revisions
make/solaris/platform_sparc.gcc file | annotate | diff | comparison | revisions
make/solaris/platform_sparcv9 file | annotate | diff | comparison | revisions
make/solaris/platform_sparcv9.gcc file | annotate | diff | comparison | revisions
make/windows/makefiles/vm.make file | annotate | diff | comparison | revisions
make/windows/platform_amd64 file | annotate | diff | comparison | revisions
make/windows/platform_i486 file | annotate | diff | comparison | revisions
src/cpu/sparc/vm/disassembler_sparc.cpp file | annotate | diff | comparison | revisions
src/cpu/x86/vm/disassembler_x86.cpp file | annotate | diff | comparison | revisions
src/share/vm/compiler/disassemblerEnv.hpp file | annotate | diff | comparison | revisions
     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 +

mercurial