Merge
authorkamg
Fri, 11 Apr 2008 09:56:35 -0400
changeset 357 f4edb0d9f109
parent 340 6d459cd56f37 (current diff)
parent 356 b5ca660b4072 (diff)
child 360 21d113ecbf6a
Merge
hotspot/.hgignore
hotspot/make/linux/makefiles/vm.make
hotspot/make/linux/platform_amd64
hotspot/make/linux/platform_i486
hotspot/make/linux/platform_sparc
hotspot/make/solaris/makefiles/vm.make
hotspot/make/solaris/platform_amd64
hotspot/make/solaris/platform_amd64.gcc
hotspot/make/solaris/platform_i486
hotspot/make/solaris/platform_i486.gcc
hotspot/make/solaris/platform_sparc
hotspot/make/solaris/platform_sparc.gcc
hotspot/make/solaris/platform_sparcv9
hotspot/make/solaris/platform_sparcv9.gcc
hotspot/make/windows/makefiles/vm.make
hotspot/make/windows/platform_amd64
hotspot/make/windows/platform_i486
hotspot/src/cpu/sparc/vm/disassembler_sparc.cpp
hotspot/src/cpu/x86/vm/disassembler_x86.cpp
hotspot/src/share/vm/compiler/disassemblerEnv.hpp
--- a/hotspot/.hgignore	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/.hgignore	Fri Apr 11 09:56:35 2008 -0400
@@ -1,3 +1,4 @@
 ^build/
 ^dist/
 ^nbproject/private/
+^src/share/tools/hsdis/bin/
--- a/hotspot/make/linux/makefiles/vm.make	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/make/linux/makefiles/vm.make	Fri Apr 11 09:56:35 2008 -0400
@@ -71,6 +71,7 @@
 # The following variables are defined in the generated flags.make file.
 BUILD_VERSION = -DHOTSPOT_RELEASE_VERSION="\"$(HS_BUILD_VER)\""
 JRE_VERSION   = -DJRE_RELEASE_VERSION="\"$(JRE_RELEASE_VER)\""
+HS_LIB_ARCH   = -DHOTSPOT_LIB_ARCH=\"$(LIBARCH)\"
 BUILD_TARGET  = -DHOTSPOT_BUILD_TARGET="\"$(TARGET)\""
 BUILD_USER    = -DHOTSPOT_BUILD_USER="\"$(HOTSPOT_BUILD_USER)\""
 VM_DISTRO     = -DHOTSPOT_VM_DISTRO="\"$(HOTSPOT_VM_DISTRO)\""
@@ -81,6 +82,7 @@
   ${BUILD_VERSION}   \
   ${BUILD_TARGET}    \
   ${BUILD_USER}      \
+  ${HS_LIB_ARCH}     \
   ${JRE_VERSION}     \
   ${VM_DISTRO}
 
--- a/hotspot/make/linux/platform_amd64	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/make/linux/platform_amd64	Fri Apr 11 09:56:35 2008 -0400
@@ -12,6 +12,4 @@
 
 compiler = gcc
 
-gnu_dis_arch = amd64
-
 sysdefs = -DLINUX -D_GNU_SOURCE -DAMD64
--- a/hotspot/make/linux/platform_i486	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/make/linux/platform_i486	Fri Apr 11 09:56:35 2008 -0400
@@ -12,6 +12,4 @@
 
 compiler = gcc
 
-gnu_dis_arch = i386
-
 sysdefs = -DLINUX -D_GNU_SOURCE -DIA32
--- a/hotspot/make/linux/platform_sparc	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/make/linux/platform_sparc	Fri Apr 11 09:56:35 2008 -0400
@@ -12,6 +12,4 @@
 
 compiler = gcc
 
-gnu_dis_arch = sparc
-
 sysdefs = -DLINUX -D_GNU_SOURCE -DSPARC
--- a/hotspot/make/solaris/makefiles/vm.make	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/make/solaris/makefiles/vm.make	Fri Apr 11 09:56:35 2008 -0400
@@ -63,6 +63,7 @@
 # The following variables are defined in the generated flags.make file.
 BUILD_VERSION = -DHOTSPOT_RELEASE_VERSION="\"$(HS_BUILD_VER)\""
 JRE_VERSION   = -DJRE_RELEASE_VERSION="\"$(JRE_RELEASE_VER)\""
+HS_LIB_ARCH   = -DHOTSPOT_LIB_ARCH=\"$(LIBARCH)\"
 BUILD_TARGET  = -DHOTSPOT_BUILD_TARGET="\"$(TARGET)\""
 BUILD_USER    = -DHOTSPOT_BUILD_USER="\"$(HOTSPOT_BUILD_USER)\""
 VM_DISTRO     = -DHOTSPOT_VM_DISTRO="\"$(HOTSPOT_VM_DISTRO)\""
@@ -73,6 +74,7 @@
   ${BUILD_VERSION}   \
   ${BUILD_TARGET}    \
   ${BUILD_USER}      \
+  ${HS_LIB_ARCH}     \
   ${JRE_VERSION}     \
   ${VM_DISTRO}
 
--- a/hotspot/make/solaris/platform_amd64	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/make/solaris/platform_amd64	Fri Apr 11 09:56:35 2008 -0400
@@ -12,6 +12,4 @@
 
 compiler = sparcWorks
 
-gnu_dis_arch = amd64
-
 sysdefs = -DSOLARIS -DSPARC_WORKS -DAMD64
--- a/hotspot/make/solaris/platform_amd64.gcc	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/make/solaris/platform_amd64.gcc	Fri Apr 11 09:56:35 2008 -0400
@@ -12,6 +12,4 @@
 
 compiler = gcc
 
-gnu_dis_arch = amd64
-
 sysdefs = -DSOLARIS -D_GNU_SOURCE  -DAMD64
--- a/hotspot/make/solaris/platform_i486	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/make/solaris/platform_i486	Fri Apr 11 09:56:35 2008 -0400
@@ -12,6 +12,4 @@
 
 compiler = sparcWorks
 
-gnu_dis_arch = i386
-
 sysdefs = -DSOLARIS -DSPARC_WORKS -DIA32
--- a/hotspot/make/solaris/platform_i486.gcc	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/make/solaris/platform_i486.gcc	Fri Apr 11 09:56:35 2008 -0400
@@ -12,6 +12,4 @@
 
 compiler = gcc
 
-gnu_dis_arch = i386
-
 sysdefs = -DSOLARIS -D_GNU_SOURCE -DIA32
--- a/hotspot/make/solaris/platform_sparc	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/make/solaris/platform_sparc	Fri Apr 11 09:56:35 2008 -0400
@@ -12,6 +12,4 @@
 
 compiler = sparcWorks
 
-gnu_dis_arch = sparc
-
 sysdefs = -DSOLARIS -DSPARC_WORKS -DSPARC
--- a/hotspot/make/solaris/platform_sparc.gcc	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/make/solaris/platform_sparc.gcc	Fri Apr 11 09:56:35 2008 -0400
@@ -12,6 +12,4 @@
 
 compiler = gcc
 
-gnu_dis_arch = sparc
-
 sysdefs = -DSOLARIS -D_GNU_SOURCE -DSPARC
--- a/hotspot/make/solaris/platform_sparcv9	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/make/solaris/platform_sparcv9	Fri Apr 11 09:56:35 2008 -0400
@@ -8,10 +8,8 @@
 
 os_arch_model = solaris_sparc
 
-lib_arch = sparc
+lib_arch = sparcv9
 
 compiler = sparcWorks
 
-gnu_dis_arch = sparc
-
 sysdefs = -DSOLARIS -DSPARC_WORKS -DSPARC
--- a/hotspot/make/solaris/platform_sparcv9.gcc	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/make/solaris/platform_sparcv9.gcc	Fri Apr 11 09:56:35 2008 -0400
@@ -8,10 +8,8 @@
 
 os_arch_model = solaris_sparc
 
-lib_arch = sparc
+lib_arch = sparcv9
 
 compiler = gcc
 
-gnu_dis_arch = sparc
-
 sysdefs = -DSOLARIS -D_GNU_SOURCE -DSPARC
--- a/hotspot/make/windows/makefiles/vm.make	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/make/windows/makefiles/vm.make	Fri Apr 11 09:56:35 2008 -0400
@@ -58,6 +58,7 @@
 # The following variables are defined in the generated local.make file.
 CPP_FLAGS=$(CPP_FLAGS) /D "HOTSPOT_RELEASE_VERSION=\"$(HS_BUILD_VER)\""
 CPP_FLAGS=$(CPP_FLAGS) /D "JRE_RELEASE_VERSION=\"$(JRE_RELEASE_VER)\""
+CPP_FLAGS=$(CPP_FLAGS) /D "HOTSPOT_LIB_ARCH=\"$(BUILDARCH)\""
 CPP_FLAGS=$(CPP_FLAGS) /D "HOTSPOT_BUILD_TARGET=\"$(BUILD_FLAVOR)\""
 CPP_FLAGS=$(CPP_FLAGS) /D "HOTSPOT_BUILD_USER=\"$(BuildUser)\""
 CPP_FLAGS=$(CPP_FLAGS) /D "HOTSPOT_VM_DISTRO=\"$(HOTSPOT_VM_DISTRO)\""
--- a/hotspot/make/windows/platform_amd64	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/make/windows/platform_amd64	Fri Apr 11 09:56:35 2008 -0400
@@ -10,6 +10,6 @@
 
 os_arch_model = windows_x86_64
 
-compiler = visCPP
+lib_arch = amd64
 
-gnu_dis_arch = amd64
+compiler = visCPP
--- a/hotspot/make/windows/platform_i486	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/make/windows/platform_i486	Fri Apr 11 09:56:35 2008 -0400
@@ -10,7 +10,6 @@
 
 os_arch_model = windows_x86_32
 
-compiler = visCPP
+lib_arch = i386
 
-gnu_dis_arch = i386
-
+compiler = visCPP
--- a/hotspot/src/cpu/sparc/vm/disassembler_sparc.cpp	Thu Apr 10 15:49:16 2008 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,230 +0,0 @@
-/*
- * Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- *
- */
-
-# include "incls/_precompiled.incl"
-# include "incls/_disassembler_sparc.cpp.incl"
-
-#ifndef PRODUCT
-
-#define SPARC_VERSION (VM_Version::v9_instructions_work()?              \
-                        (VM_Version::v8_instructions_work()? "" : "9") : "8")
-
-// This routine is in the shared library:
-typedef unsigned char* print_insn_sparc_t(unsigned char* start, DisassemblerEnv* env,
-                                          const char* sparc_version);
-
-void*    Disassembler::_library          = NULL;
-dll_func Disassembler::_print_insn_sparc = NULL;
-
-bool Disassembler::load_library() {
-  if (_library == NULL) {
-    char buf[1024];
-    char ebuf[1024];
-    sprintf(buf, "disassembler%s", os::dll_file_extension());
-    _library = hpi::dll_load(buf, ebuf, sizeof ebuf);
-    if (_library != NULL) {
-      tty->print_cr("Loaded disassembler");
-      _print_insn_sparc = CAST_TO_FN_PTR(dll_func, hpi::dll_lookup(_library, "print_insn_sparc"));
-    }
-  }
-  return (_library != NULL) && (_print_insn_sparc != NULL);
-}
-
-
-class sparc_env : public DisassemblerEnv {
- private:
-  nmethod*      code;
-  outputStream* output;
-  const char*   version;
-
-  static void print_address(address value, outputStream* st);
-
- public:
-  sparc_env(nmethod* rcode, outputStream* routput) {
-    code    = rcode;
-    output  = routput;
-    version = SPARC_VERSION;
-  }
-  const char* sparc_version() { return version; }
-  void print_label(intptr_t value);
-  void print_raw(char* str) { output->print_raw(str); }
-  void print(char* format, ...);
-  char* string_for_offset(intptr_t value);
-  char* string_for_constant(unsigned char* pc, intptr_t value, int is_decimal);
-};
-
-
-void sparc_env::print_address(address adr, outputStream* st) {
-  if (!Universe::is_fully_initialized()) {
-    st->print(INTPTR_FORMAT, (intptr_t)adr);
-    return;
-  }
-  if (StubRoutines::contains(adr)) {
-    StubCodeDesc *desc = StubCodeDesc::desc_for(adr);
-    if (desc == NULL)
-      desc = StubCodeDesc::desc_for(adr + frame::pc_return_offset);
-    if (desc == NULL)
-      st->print("Unknown stub at " INTPTR_FORMAT, adr);
-    else {
-      st->print("Stub::%s", desc->name());
-      if (desc->begin() != adr)
-        st->print("%+d 0x%p",adr - desc->begin(), adr);
-      else if (WizardMode) st->print(" " INTPTR_FORMAT, adr);
-    }
-  } else {
-    BarrierSet* bs = Universe::heap()->barrier_set();
-    if (bs->kind() == BarrierSet::CardTableModRef &&
-        adr == (address)((CardTableModRefBS*)(bs))->byte_map_base) {
-      st->print("word_map_base");
-      if (WizardMode) st->print(" " INTPTR_FORMAT, (intptr_t)adr);
-    } else {
-      st->print(INTPTR_FORMAT, (intptr_t)adr);
-    }
-  }
-}
-
-
-// called by the disassembler to print out jump addresses
-void sparc_env::print_label(intptr_t value) {
-  print_address((address) value, output);
-}
-
-void sparc_env::print(char* format, ...) {
-  va_list ap;
-  va_start(ap, format);
-  output->vprint(format, ap);
-  va_end(ap);
-}
-
-char* sparc_env::string_for_offset(intptr_t value) {
-  stringStream st;
-  print_address((address) value, &st);
-  return st.as_string();
-}
-
-char* sparc_env::string_for_constant(unsigned char* pc, intptr_t value, int is_decimal) {
-  stringStream st;
-  oop obj;
-  if (code && (obj = code->embeddedOop_at(pc)) != NULL) {
-    obj->print_value_on(&st);
-  } else
-  {
-    print_address((address) value, &st);
-  }
-  return st.as_string();
-}
-
-
-address Disassembler::decode_instruction(address start, DisassemblerEnv* env) {
-  const char* version = ((sparc_env*)env)->sparc_version();
-  return ((print_insn_sparc_t*) _print_insn_sparc)(start, env, version);
-}
-
-
-const int show_bytes = false; // for disassembler debugging
-
-
-void Disassembler::decode(CodeBlob* cb, outputStream* st) {
-  st = st ? st : tty;
-  st->print_cr("Decoding CodeBlob " INTPTR_FORMAT, cb);
-  decode(cb->instructions_begin(), cb->instructions_end(), st);
-}
-
-
-void Disassembler::decode(u_char* begin, u_char* end, outputStream* st) {
-  assert ((((intptr_t)begin | (intptr_t)end) % sizeof(int) == 0), "misaligned insn addr");
-  st = st ? st : tty;
-  if (!load_library()) {
-    st->print_cr("Could not load disassembler");
-    return;
-  }
-  sparc_env env(NULL, st);
-  unsigned char*  p = (unsigned char*) begin;
-  CodeBlob* cb = CodeCache::find_blob_unsafe(begin);
-  while (p < (unsigned char*) end && p) {
-    if (cb != NULL) {
-      cb->print_block_comment(st, (intptr_t)(p - cb->instructions_begin()));
-    }
-
-    unsigned char* p0 = p;
-    st->print(INTPTR_FORMAT ": ", p);
-    p = decode_instruction(p, &env);
-    if (show_bytes && p) {
-      st->print("\t\t\t");
-      while (p0 < p) { st->print("%08lx ", *(int*)p0); p0 += sizeof(int); }
-    }
-    st->cr();
-  }
-}
-
-
-void Disassembler::decode(nmethod* nm, outputStream* st) {
-  st = st ? st : tty;
-
-  st->print_cr("Decoding compiled method " INTPTR_FORMAT ":", nm);
-  st->print("Code:");
-  st->cr();
-
-  if (!load_library()) {
-    st->print_cr("Could not load disassembler");
-    return;
-  }
-  sparc_env env(nm, st);
-  unsigned char* p   = nm->instructions_begin();
-  unsigned char* end = nm->instructions_end();
-  assert ((((intptr_t)p | (intptr_t)end) % sizeof(int) == 0), "misaligned insn addr");
-
-  unsigned char *p1 = p;
-  int total_bucket_count = 0;
-  while (p1 < end && p1) {
-    unsigned char *p0 = p1;
-    ++p1;
-    address bucket_pc = FlatProfiler::bucket_start_for(p1);
-    if (bucket_pc != NULL && bucket_pc > p0 && bucket_pc <= p1)
-      total_bucket_count += FlatProfiler::bucket_count_for(p0);
-  }
-
-  while (p < end && p) {
-    if (p == nm->entry_point())                     st->print_cr("[Entry Point]");
-    if (p == nm->verified_entry_point())            st->print_cr("[Verified Entry Point]");
-    if (p == nm->exception_begin())                 st->print_cr("[Exception Handler]");
-    if (p == nm->stub_begin())                      st->print_cr("[Stub Code]");
-    if (p == nm->consts_begin())                    st->print_cr("[Constants]");
-    nm->print_block_comment(st, (intptr_t)(p - nm->instructions_begin()));
-    unsigned char* p0 = p;
-    st->print("  " INTPTR_FORMAT ": ", p);
-    p = decode_instruction(p, &env);
-    nm->print_code_comment_on(st, 40, p0, p);
-    st->cr();
-    // Output pc bucket ticks if we have any
-    address bucket_pc = FlatProfiler::bucket_start_for(p);
-    if (bucket_pc != NULL && bucket_pc > p0 && bucket_pc <= p) {
-      int bucket_count = FlatProfiler::bucket_count_for(p0);
-      tty->print_cr("%3.1f%% [%d]", bucket_count*100.0/total_bucket_count, bucket_count);
-      tty->cr();
-    }
-  }
-}
-
-#endif // PRODUCT
--- a/hotspot/src/cpu/sparc/vm/disassembler_sparc.hpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/cpu/sparc/vm/disassembler_sparc.hpp	Fri Apr 11 09:56:35 2008 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-1999 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2008 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,30 +22,11 @@
  *
  */
 
-// The disassembler prints out sparc code annotated
-// with Java specific information.
+  static int pd_instruction_alignment() {
+    return sizeof(int);
+  }
 
-class Disassembler {
-#ifndef PRODUCT
- private:
-  // points to the library.
-  static void*    _library;
-  // points to the print_insn_sparc function.
-  static dll_func _print_insn_sparc;
-  // tries to load library and return whether it succedded.
-  static bool load_library();
-  // decodes one instruction and return the start of the next instruction.
-  static address decode_instruction(address start, DisassemblerEnv* env);
-#endif
- public:
-  static void decode(CodeBlob *cb,               outputStream* st = NULL) PRODUCT_RETURN;
-  static void decode(nmethod* nm,                outputStream* st = NULL) PRODUCT_RETURN;
-  static void decode(u_char* begin, u_char* end, outputStream* st = NULL) PRODUCT_RETURN;
-};
-
-//Reconciliation History
-// 1.9 98/04/29 10:45:51 disassembler_i486.hpp
-// 1.10 98/05/11 16:47:20 disassembler_i486.hpp
-// 1.12 99/06/22 16:37:37 disassembler_i486.hpp
-// 1.13 99/08/06 10:09:04 disassembler_i486.hpp
-//End
+  static const char* pd_cpu_opts() {
+    return (VM_Version::v9_instructions_work()?
+            (VM_Version::v8_instructions_work()? "" : "v9only") : "v8only");
+  }
--- a/hotspot/src/cpu/sparc/vm/frame_sparc.cpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/cpu/sparc/vm/frame_sparc.cpp	Fri Apr 11 09:56:35 2008 -0400
@@ -157,22 +157,158 @@
   check_location_valid();
 }
 
+bool frame::safe_for_sender(JavaThread *thread) {
 
-bool frame::safe_for_sender(JavaThread *thread) {
-  address   sp = (address)_sp;
-  if (sp != NULL &&
-      (sp <= thread->stack_base() && sp >= thread->stack_base() - thread->stack_size())) {
-      // Unfortunately we can only check frame complete for runtime stubs and nmethod
-      // other generic buffer blobs are more problematic so we just assume they are
-      // ok. adapter blobs never have a frame complete and are never ok.
-      if (_cb != NULL && !_cb->is_frame_complete_at(_pc)) {
-        if (_cb->is_nmethod() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) {
-          return false;
-        }
+  address _SP = (address) sp();
+  address _FP = (address) fp();
+  address _UNEXTENDED_SP = (address) unextended_sp();
+  // sp must be within the stack
+  bool sp_safe = (_SP <= thread->stack_base()) &&
+                 (_SP >= thread->stack_base() - thread->stack_size());
+
+  if (!sp_safe) {
+    return false;
+  }
+
+  // unextended sp must be within the stack and above or equal sp
+  bool unextended_sp_safe = (_UNEXTENDED_SP <= thread->stack_base()) &&
+                            (_UNEXTENDED_SP >= _SP);
+
+  if (!unextended_sp_safe) return false;
+
+  // an fp must be within the stack and above (but not equal) sp
+  bool fp_safe = (_FP <= thread->stack_base()) &&
+                 (_FP > _SP);
+
+  // We know sp/unextended_sp are safe only fp is questionable here
+
+  // If the current frame is known to the code cache then we can attempt to
+  // to construct the sender and do some validation of it. This goes a long way
+  // toward eliminating issues when we get in frame construction code
+
+  if (_cb != NULL ) {
+
+    // First check if frame is complete and tester is reliable
+    // Unfortunately we can only check frame complete for runtime stubs and nmethod
+    // other generic buffer blobs are more problematic so we just assume they are
+    // ok. adapter blobs never have a frame complete and are never ok.
+
+    if (!_cb->is_frame_complete_at(_pc)) {
+      if (_cb->is_nmethod() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) {
+        return false;
+      }
+    }
+
+    // Entry frame checks
+    if (is_entry_frame()) {
+      // an entry frame must have a valid fp.
+
+      if (!fp_safe) {
+        return false;
       }
-      return true;
+
+      // Validate the JavaCallWrapper an entry frame must have
+
+      address jcw = (address)entry_frame_call_wrapper();
+
+      bool jcw_safe = (jcw <= thread->stack_base()) && ( jcw > _FP);
+
+      return jcw_safe;
+
+    }
+
+    intptr_t* younger_sp = sp();
+    intptr_t* _SENDER_SP = sender_sp(); // sender is actually just _FP
+    bool adjusted_stack = is_interpreted_frame();
+
+    address   sender_pc = (address)younger_sp[I7->sp_offset_in_saved_window()] + pc_return_offset;
+
+
+    // We must always be able to find a recognizable pc
+    CodeBlob* sender_blob = CodeCache::find_blob_unsafe(sender_pc);
+    if (sender_pc == NULL ||  sender_blob == NULL) {
+      return false;
+    }
+
+    // It should be safe to construct the sender though it might not be valid
+
+    frame sender(_SENDER_SP, younger_sp, adjusted_stack);
+
+    // Do we have a valid fp?
+    address sender_fp = (address) sender.fp();
+
+    // an fp must be within the stack and above (but not equal) current frame's _FP
+
+    bool sender_fp_safe = (sender_fp <= thread->stack_base()) &&
+                   (sender_fp > _FP);
+
+    if (!sender_fp_safe) {
+      return false;
+    }
+
+
+    // If the potential sender is the interpreter then we can do some more checking
+    if (Interpreter::contains(sender_pc)) {
+      return sender.is_interpreted_frame_valid(thread);
+    }
+
+    // Could just be some random pointer within the codeBlob
+    if (!sender.cb()->instructions_contains(sender_pc)) return false;
+
+    // We should never be able to see an adapter if the current frame is something from code cache
+
+    if ( sender_blob->is_adapter_blob()) {
+      return false;
+    }
+
+    if( sender.is_entry_frame()) {
+      // Validate the JavaCallWrapper an entry frame must have
+
+      address jcw = (address)sender.entry_frame_call_wrapper();
+
+      bool jcw_safe = (jcw <= thread->stack_base()) && ( jcw > sender_fp);
+
+      return jcw_safe;
+    }
+
+    // If the frame size is 0 something is bad because every nmethod has a non-zero frame size
+    // because you must allocate window space
+
+    if (sender_blob->frame_size() == 0) {
+      assert(!sender_blob->is_nmethod(), "should count return address at least");
+      return false;
+    }
+
+    // The sender should positively be an nmethod or call_stub. On sparc we might in fact see something else.
+    // The cause of this is because at a save instruction the O7 we get is a leftover from an earlier
+    // window use. So if a runtime stub creates two frames (common in fastdebug/jvmg) then we see the
+    // stale pc. So if the sender blob is not something we'd expect we have little choice but to declare
+    // the stack unwalkable. pd_get_top_frame_for_signal_handler tries to recover from this by unwinding
+    // that initial frame and retrying.
+
+    if (!sender_blob->is_nmethod()) {
+      return false;
+    }
+
+    // Could put some more validation for the potential non-interpreted sender
+    // frame we'd create by calling sender if I could think of any. Wait for next crash in forte...
+
+    // One idea is seeing if the sender_pc we have is one that we'd expect to call to current cb
+
+    // We've validated the potential sender that would be created
+
+    return true;
+
   }
-  return false;
+
+  // Must be native-compiled frame. Since sender will try and use fp to find
+  // linkages it must be safe
+
+  if (!fp_safe) return false;
+
+  // could try and do some more potential verification of native frame if we could think of some...
+
+  return true;
 }
 
 // constructors
@@ -450,7 +586,7 @@
 }
 
 
-bool frame::is_interpreted_frame_valid() const {
+bool frame::is_interpreted_frame_valid(JavaThread* thread) const {
 #ifdef CC_INTERP
   // Is there anything to do?
 #else
@@ -462,6 +598,7 @@
   if (sp() == 0 || (intptr_t(sp()) & (2*wordSize-1)) != 0) {
     return false;
   }
+
   const intptr_t interpreter_frame_initial_sp_offset = interpreter_frame_vm_local_words;
   if (fp() + interpreter_frame_initial_sp_offset < sp()) {
     return false;
@@ -471,9 +608,43 @@
   if (fp() <= sp()) {        // this attempts to deal with unsigned comparison above
     return false;
   }
-  if (fp() - sp() > 4096) {  // stack frames shouldn't be large.
+  // do some validation of frame elements
+
+  // first the method
+
+  methodOop m = *interpreter_frame_method_addr();
+
+  // validate the method we'd find in this potential sender
+  if (!Universe::heap()->is_valid_method(m)) return false;
+
+  // stack frames shouldn't be much larger than max_stack elements
+
+  if (fp() - sp() > 1024 + m->max_stack()*Interpreter::stackElementSize()) {
     return false;
   }
+
+  // validate bci/bcx
+
+  intptr_t  bcx    = interpreter_frame_bcx();
+  if (m->validate_bci_from_bcx(bcx) < 0) {
+    return false;
+  }
+
+  // validate constantPoolCacheOop
+
+  constantPoolCacheOop cp = *interpreter_frame_cache_addr();
+
+  if (cp == NULL ||
+      !Space::is_aligned(cp) ||
+      !Universe::heap()->is_permanent((void*)cp)) return false;
+
+  // validate locals
+
+  address locals =  (address) *interpreter_frame_locals_addr();
+
+  if (locals > thread->stack_base() || locals < (address) fp()) return false;
+
+  // We'd have to be pretty unlucky to be mislead at this point
 #endif /* CC_INTERP */
   return true;
 }
--- a/hotspot/src/cpu/x86/vm/disassembler_x86.cpp	Thu Apr 10 15:49:16 2008 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,201 +0,0 @@
-/*
- * Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- *
- */
-
-# include "incls/_precompiled.incl"
-# include "incls/_disassembler_x86.cpp.incl"
-
-#ifndef PRODUCT
-
-void*    Disassembler::_library            = NULL;
-Disassembler::decode_func Disassembler::_decode_instruction = NULL;
-
-bool Disassembler::load_library() {
-  if (_library == NULL) {
-    char buf[1024];
-    char ebuf[1024];
-    sprintf(buf, "disassembler%s", os::dll_file_extension());
-    _library = hpi::dll_load(buf, ebuf, sizeof ebuf);
-    if (_library != NULL) {
-      tty->print_cr("Loaded disassembler");
-      _decode_instruction = CAST_TO_FN_PTR(Disassembler::decode_func, hpi::dll_lookup(_library, "decode_instruction"));
-    }
-  }
-  return (_library != NULL) && (_decode_instruction != NULL);
-}
-
-class x86_env : public DisassemblerEnv {
- private:
-  nmethod*      code;
-  outputStream* output;
- public:
-  x86_env(nmethod* rcode, outputStream* routput) {
-    code   = rcode;
-    output = routput;
-  }
-  void print_label(intptr_t value);
-  void print_raw(char* str) { output->print_raw(str); }
-  void print(char* format, ...);
-  char* string_for_offset(intptr_t value);
-  char* string_for_constant(unsigned char* pc, intptr_t value, int is_decimal);
-};
-
-
-void x86_env::print_label(intptr_t value) {
-  if (!Universe::is_fully_initialized()) {
-    output->print(INTPTR_FORMAT, value);
-    return;
-  }
-  address adr = (address) value;
-  if (StubRoutines::contains(adr)) {
-    StubCodeDesc* desc = StubCodeDesc::desc_for(adr);
-    const char * desc_name = "unknown stub";
-    if (desc != NULL) {
-      desc_name = desc->name();
-    }
-    output->print("Stub::%s", desc_name);
-    if (WizardMode) output->print(" " INTPTR_FORMAT, value);
-  } else {
-    output->print(INTPTR_FORMAT, value);
-  }
-}
-
-void x86_env::print(char* format, ...) {
-  va_list ap;
-  va_start(ap, format);
-  output->vprint(format, ap);
-  va_end(ap);
-}
-
-char* x86_env::string_for_offset(intptr_t value) {
-  stringStream st;
-  if (!Universe::is_fully_initialized()) {
-    st.print(INTX_FORMAT, value);
-    return st.as_string();
-  }
-  BarrierSet* bs = Universe::heap()->barrier_set();
-  BarrierSet::Name bsn = bs->kind();
-  if (bs->kind() == BarrierSet::CardTableModRef &&
-      (jbyte*) value == ((CardTableModRefBS*)(bs))->byte_map_base) {
-    st.print("word_map_base");
-  } else {
-    st.print(INTX_FORMAT, value);
-  }
-  return st.as_string();
-}
-
-char* x86_env::string_for_constant(unsigned char* pc, intptr_t value, int is_decimal) {
-  stringStream st;
-  oop obj = NULL;
-  if (code && ((obj = code->embeddedOop_at(pc)) != NULL)) {
-    obj->print_value_on(&st);
-  } else {
-    if (is_decimal == 1) {
-      st.print(INTX_FORMAT, value);
-    } else {
-      st.print(INTPTR_FORMAT, value);
-    }
-  }
-  return st.as_string();
-}
-
-
-
-address Disassembler::decode_instruction(address start, DisassemblerEnv* env) {
-  return ((decode_func) _decode_instruction)(start, env);
-}
-
-
-void Disassembler::decode(CodeBlob* cb, outputStream* st) {
-  st = st ? st : tty;
-  st->print_cr("Decoding CodeBlob " INTPTR_FORMAT, cb);
-  decode(cb->instructions_begin(), cb->instructions_end(), st);
-}
-
-
-void Disassembler::decode(u_char* begin, u_char* end, outputStream* st) {
-  st = st ? st : tty;
-
-  const int show_bytes = false; // for disassembler debugging
-
-  if (!load_library()) {
-    st->print_cr("Could not load disassembler");
-    return;
-  }
-
-  x86_env env(NULL, st);
-  unsigned char*  p = (unsigned char*) begin;
-  CodeBlob* cb = CodeCache::find_blob_unsafe(begin);
-  while (p < (unsigned char*) end) {
-    if (cb != NULL) {
-      cb->print_block_comment(st, (intptr_t)(p - cb->instructions_begin()));
-    }
-
-    unsigned char* p0 = p;
-    st->print("  " INTPTR_FORMAT ": ", p);
-    p = decode_instruction(p, &env);
-    if (show_bytes) {
-      st->print("\t\t\t");
-      while (p0 < p) st->print("%x ", *p0++);
-    }
-    st->cr();
-  }
-}
-
-
-void Disassembler::decode(nmethod* nm, outputStream* st) {
-  st = st ? st : tty;
-
-  st->print_cr("Decoding compiled method " INTPTR_FORMAT ":", nm);
-  st->print("Code:");
-  st->cr();
-
-  if (!load_library()) {
-    st->print_cr("Could not load disassembler");
-    return;
-  }
-  x86_env env(nm, st);
-  unsigned char* p = nm->instructions_begin();
-  unsigned char* end = nm->instructions_end();
-  while (p < end) {
-    if (p == nm->entry_point())             st->print_cr("[Entry Point]");
-    if (p == nm->verified_entry_point())    st->print_cr("[Verified Entry Point]");
-    if (p == nm->exception_begin())         st->print_cr("[Exception Handler]");
-    if (p == nm->stub_begin())              st->print_cr("[Stub Code]");
-    if (p == nm->consts_begin())            st->print_cr("[Constants]");
-    nm->print_block_comment(st, (intptr_t)(p - nm->instructions_begin()));
-    unsigned char* p0 = p;
-    st->print("  " INTPTR_FORMAT ": ", p);
-    p = decode_instruction(p, &env);
-    nm->print_code_comment_on(st, 40, p0, p);
-    st->cr();
-    // Output pc bucket ticks if we have any
-    address bucket_pc = FlatProfiler::bucket_start_for(p);
-    if (bucket_pc != NULL && bucket_pc > p0 && bucket_pc <= p) {
-      int bucket_count = FlatProfiler::bucket_count_for(bucket_pc);
-      tty->print_cr("[%d]", bucket_count);
-    }
-  }
-}
-
-#endif // PRODUCT
--- a/hotspot/src/cpu/x86/vm/disassembler_x86.hpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/cpu/x86/vm/disassembler_x86.hpp	Fri Apr 11 09:56:35 2008 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-1999 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2008 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,24 +22,10 @@
  *
  */
 
-// The disassembler prints out intel 386 code annotated
-// with Java specific information.
+  static int pd_instruction_alignment() {
+    return 1;
+  }
 
-class Disassembler {
-#ifndef PRODUCT
- private:
-  typedef address (*decode_func)(address start, DisassemblerEnv* env);
-  // points the library.
-  static void*    _library;
-  // points to the decode function.
-  static decode_func _decode_instruction;
-  // tries to load library and return whether it succedded.
-  static bool load_library();
-  // decodes one instruction and return the start of the next instruction.
-  static address decode_instruction(address start, DisassemblerEnv* env);
-#endif
- public:
-  static void decode(CodeBlob *cb,               outputStream* st = NULL) PRODUCT_RETURN;
-  static void decode(nmethod* nm,                outputStream* st = NULL) PRODUCT_RETURN;
-  static void decode(u_char* begin, u_char* end, outputStream* st = NULL) PRODUCT_RETURN;
-};
+  static const char* pd_cpu_opts() {
+    return "";
+  }
--- a/hotspot/src/cpu/x86/vm/frame_x86.cpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/cpu/x86/vm/frame_x86.cpp	Fri Apr 11 09:56:35 2008 -0400
@@ -37,39 +37,181 @@
   address   sp = (address)_sp;
   address   fp = (address)_fp;
   address   unextended_sp = (address)_unextended_sp;
-  bool sp_safe = (sp != NULL &&
-                 (sp <= thread->stack_base()) &&
-                 (sp >= thread->stack_base() - thread->stack_size()));
-  bool unextended_sp_safe = (unextended_sp != NULL &&
-                 (unextended_sp <= thread->stack_base()) &&
-                 (unextended_sp >= thread->stack_base() - thread->stack_size()));
-  bool fp_safe = (fp != NULL &&
-                 (fp <= thread->stack_base()) &&
-                 (fp >= thread->stack_base() - thread->stack_size()));
-  if (sp_safe && unextended_sp_safe && fp_safe) {
+  // sp must be within the stack
+  bool sp_safe = (sp <= thread->stack_base()) &&
+                 (sp >= thread->stack_base() - thread->stack_size());
+
+  if (!sp_safe) {
+    return false;
+  }
+
+  // unextended sp must be within the stack and above or equal sp
+  bool unextended_sp_safe = (unextended_sp <= thread->stack_base()) &&
+                            (unextended_sp >= sp);
+
+  if (!unextended_sp_safe) {
+    return false;
+  }
+
+  // an fp must be within the stack and above (but not equal) sp
+  bool fp_safe = (fp <= thread->stack_base()) && (fp > sp);
+
+  // We know sp/unextended_sp are safe only fp is questionable here
+
+  // If the current frame is known to the code cache then we can attempt to
+  // to construct the sender and do some validation of it. This goes a long way
+  // toward eliminating issues when we get in frame construction code
+
+  if (_cb != NULL ) {
+
+    // First check if frame is complete and tester is reliable
     // Unfortunately we can only check frame complete for runtime stubs and nmethod
     // other generic buffer blobs are more problematic so we just assume they are
     // ok. adapter blobs never have a frame complete and are never ok.
-    if (_cb != NULL && !_cb->is_frame_complete_at(_pc)) {
+
+    if (!_cb->is_frame_complete_at(_pc)) {
       if (_cb->is_nmethod() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) {
         return false;
       }
     }
+    // Entry frame checks
+    if (is_entry_frame()) {
+      // an entry frame must have a valid fp.
+
+      if (!fp_safe) return false;
+
+      // Validate the JavaCallWrapper an entry frame must have
+
+      address jcw = (address)entry_frame_call_wrapper();
+
+      bool jcw_safe = (jcw <= thread->stack_base()) && ( jcw > fp);
+
+      return jcw_safe;
+
+    }
+
+    intptr_t* sender_sp = NULL;
+    address   sender_pc = NULL;
+
+    if (is_interpreted_frame()) {
+      // fp must be safe
+      if (!fp_safe) {
+        return false;
+      }
+
+      sender_pc = (address) this->fp()[return_addr_offset];
+      sender_sp = (intptr_t*) addr_at(sender_sp_offset);
+
+    } else {
+      // must be some sort of compiled/runtime frame
+      // fp does not have to be safe (although it could be check for c1?)
+
+      sender_sp = _unextended_sp + _cb->frame_size();
+      // On Intel the return_address is always the word on the stack
+      sender_pc = (address) *(sender_sp-1);
+    }
+
+    // We must always be able to find a recognizable pc
+    CodeBlob* sender_blob = CodeCache::find_blob_unsafe(sender_pc);
+    if (sender_pc == NULL ||  sender_blob == NULL) {
+      return false;
+    }
+
+
+    // If the potential sender is the interpreter then we can do some more checking
+    if (Interpreter::contains(sender_pc)) {
+
+      // ebp is always saved in a recognizable place in any code we generate. However
+      // only if the sender is interpreted/call_stub (c1 too?) are we certain that the saved ebp
+      // is really a frame pointer.
+
+      intptr_t *saved_fp = (intptr_t*)*(sender_sp - frame::sender_sp_offset);
+      bool saved_fp_safe = ((address)saved_fp <= thread->stack_base()) && (saved_fp > sender_sp);
+
+      if (!saved_fp_safe) {
+        return false;
+      }
+
+      // construct the potential sender
+
+      frame sender(sender_sp, saved_fp, sender_pc);
+
+      return sender.is_interpreted_frame_valid(thread);
+
+    }
+
+    // Could just be some random pointer within the codeBlob
+
+    if (!sender_blob->instructions_contains(sender_pc)) return false;
+
+    // We should never be able to see an adapter if the current frame is something from code cache
+
+    if ( sender_blob->is_adapter_blob()) {
+      return false;
+    }
+
+    // Could be the call_stub
+
+    if (StubRoutines::returns_to_call_stub(sender_pc)) {
+      intptr_t *saved_fp = (intptr_t*)*(sender_sp - frame::sender_sp_offset);
+      bool saved_fp_safe = ((address)saved_fp <= thread->stack_base()) && (saved_fp > sender_sp);
+
+      if (!saved_fp_safe) {
+        return false;
+      }
+
+      // construct the potential sender
+
+      frame sender(sender_sp, saved_fp, sender_pc);
+
+      // Validate the JavaCallWrapper an entry frame must have
+      address jcw = (address)sender.entry_frame_call_wrapper();
+
+      bool jcw_safe = (jcw <= thread->stack_base()) && ( jcw > (address)sender.fp());
+
+      return jcw_safe;
+    }
+
+    // If the frame size is 0 something is bad because every nmethod has a non-zero frame size
+    // because the return address counts against the callee's frame.
+
+    if (sender_blob->frame_size() == 0) {
+      assert(!sender_blob->is_nmethod(), "should count return address at least");
+      return false;
+    }
+
+    // We should never be able to see anything here except an nmethod. If something in the
+    // code cache (current frame) is called by an entity within the code cache that entity
+    // should not be anything but the call stub (already covered), the interpreter (already covered)
+    // or an nmethod.
+
+    assert(sender_blob->is_nmethod(), "Impossible call chain");
+
+    // Could put some more validation for the potential non-interpreted sender
+    // frame we'd create by calling sender if I could think of any. Wait for next crash in forte...
+
+    // One idea is seeing if the sender_pc we have is one that we'd expect to call to current cb
+
+    // We've validated the potential sender that would be created
     return true;
   }
-  // Note: fp == NULL is not really a prerequisite for this to be safe to
-  // walk for c2. However we've modified the code such that if we get
-  // a failure with fp != NULL that we then try with FP == NULL.
-  // This is basically to mimic what a last_frame would look like if
-  // c2 had generated it.
-  if (sp_safe && unextended_sp_safe && fp == NULL) {
-    // frame must be complete if fp == NULL as fp == NULL is only sensible
-    // if we are looking at a nmethod and frame complete assures us of that.
-    if (_cb != NULL && _cb->is_frame_complete_at(_pc) && _cb->is_compiled_by_c2()) {
-        return true;
-    }
+
+  // Must be native-compiled frame. Since sender will try and use fp to find
+  // linkages it must be safe
+
+  if (!fp_safe) {
+    return false;
   }
-  return false;
+
+  // Will the pc we fetch be non-zero (which we'll find at the oldest frame)
+
+  if ( (address) this->fp()[return_addr_offset] == NULL) return false;
+
+
+  // could try and do some more potential verification of native frame if we could think of some...
+
+  return true;
+
 }
 
 
@@ -292,7 +434,7 @@
   // nothing done here now
 }
 
-bool frame::is_interpreted_frame_valid() const {
+bool frame::is_interpreted_frame_valid(JavaThread* thread) const {
 // QQQ
 #ifdef CC_INTERP
 #else
@@ -312,9 +454,45 @@
   if (fp() <= sp()) {        // this attempts to deal with unsigned comparison above
     return false;
   }
-  if (fp() - sp() > 4096) {  // stack frames shouldn't be large.
+
+  // do some validation of frame elements
+
+  // first the method
+
+  methodOop m = *interpreter_frame_method_addr();
+
+  // validate the method we'd find in this potential sender
+  if (!Universe::heap()->is_valid_method(m)) return false;
+
+  // stack frames shouldn't be much larger than max_stack elements
+
+  if (fp() - sp() > 1024 + m->max_stack()*Interpreter::stackElementSize()) {
     return false;
   }
+
+  // validate bci/bcx
+
+  intptr_t  bcx    = interpreter_frame_bcx();
+  if (m->validate_bci_from_bcx(bcx) < 0) {
+    return false;
+  }
+
+  // validate constantPoolCacheOop
+
+  constantPoolCacheOop cp = *interpreter_frame_cache_addr();
+
+  if (cp == NULL ||
+      !Space::is_aligned(cp) ||
+      !Universe::heap()->is_permanent((void*)cp)) return false;
+
+  // validate locals
+
+  address locals =  (address) *interpreter_frame_locals_addr();
+
+  if (locals > thread->stack_base() || locals < (address) fp()) return false;
+
+  // We'd have to be pretty unlucky to be mislead at this point
+
 #endif // CC_INTERP
   return true;
 }
--- a/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp	Fri Apr 11 09:56:35 2008 -0400
@@ -72,15 +72,20 @@
   _unextended_sp = sp;
   _fp = fp;
   _pc = (address)(sp[-1]);
-  assert(_pc != NULL, "no pc?");
+
+  // Here's a sticky one. This constructor can be called via AsyncGetCallTrace
+  // when last_Java_sp is non-null but the pc fetched is junk. If we are truly
+  // unlucky the junk value could be to a zombied method and we'll die on the
+  // find_blob call. This is also why we can have no asserts on the validity
+  // of the pc we find here. AsyncGetCallTrace -> pd_get_top_frame_for_signal_handler
+  // -> pd_last_frame should use a specialized version of pd_last_frame which could
+  // call a specilaized frame constructor instead of this one.
+  // Then we could use the assert below. However this assert is of somewhat dubious
+  // value.
+  // assert(_pc != NULL, "no pc?");
+
   _cb = CodeCache::find_blob(_pc);
-  // In case of native stubs, the pc retreived here might be
-  // wrong. (the _last_native_pc will have the right value)
-  // So do not put add any asserts on the _pc here.
 
-  // QQQ The above comment is wrong and has been wrong for years. This constructor
-  // should (and MUST) not be called in that situation. In the native situation
-  // the pc should be supplied to the constructor.
   _deopt_state = not_deoptimized;
   if (_cb != NULL && _cb->is_nmethod() && ((nmethod*)_cb)->is_deopt_pc(_pc)) {
     _pc = (((nmethod*)_cb)->get_original_pc(this));
--- a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp	Fri Apr 11 09:56:35 2008 -0400
@@ -1632,7 +1632,7 @@
       // We need to prepare to execute the OSR method. First we must
       // migrate the locals and monitors off of the stack.
 
-      __ movl(rsi, rax);                             // save the nmethod
+      __ movl(rbx, rax);                             // save the nmethod
 
       const Register thread = rcx;
       __ get_thread(thread);
@@ -1688,7 +1688,7 @@
       __ pushl(rdi);
 
       // and begin the OSR nmethod
-      __ jmp(Address(rsi, nmethod::osr_entry_point_offset()));
+      __ jmp(Address(rbx, nmethod::osr_entry_point_offset()));
     }
   }
 }
--- a/hotspot/src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.cpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.cpp	Fri Apr 11 09:56:35 2008 -0400
@@ -50,17 +50,6 @@
   // even if isInJava == true. It should be more reliable than
   // ucontext info.
   if (jt->has_last_Java_frame() && jt->frame_anchor()->walkable()) {
-#if 0
-    // This sanity check may not be needed with the new frame
-    // walking code. Remove it for now.
-    if (!jt->frame_anchor()->post_Java_state_is_pc()
-    && frame::next_younger_sp_or_null(last_Java_sp(),
-    jt->frame_anchor()->post_Java_sp()) == NULL) {
-      // the anchor contains an SP, but the frame is not walkable
-      // because post_Java_sp isn't valid relative to last_Java_sp
-      return false;
-    }
-#endif
     *fr_addr = jt->pd_last_frame();
     return true;
   }
@@ -77,23 +66,59 @@
     return false;
   }
 
+  frame ret_frame(ret_sp, frame::unpatchable, addr.pc());
+
   // we were running Java code when SIGPROF came in
   if (isInJava) {
+
+
+    // If the frame we got is safe then it is most certainly valid
+    if (ret_frame.safe_for_sender(jt)) {
+      *fr_addr = ret_frame;
+      return true;
+    }
+
+    // If it isn't safe then we can try several things to try and get
+    // a good starting point.
+    //
+    // On sparc the frames are almost certainly walkable in the sense
+    // of sp/fp linkages. However because of recycling of windows if
+    // a piece of code does multiple save's where the initial save creates
+    // a real frame with a return pc and the succeeding save's are used to
+    // simply get free registers and have no real pc then the pc linkage on these
+    // "inner" temporary frames will be bogus.
+    // Since there is in general only a nesting level like
+    // this one deep in general we'll try and unwind such an "inner" frame
+    // here ourselves and see if it makes sense
+
+    frame unwind_frame(ret_frame.fp(), frame::unpatchable, addr.pc());
+
+    if (unwind_frame.safe_for_sender(jt)) {
+      *fr_addr = unwind_frame;
+      return true;
+    }
+
+    // Well that didn't work. Most likely we're toast on this tick
+    // The previous code would try this. I think it is dubious in light
+    // of changes to safe_for_sender and the unwind trick above but
+    // if it gets us a safe frame who wants to argue.
+
     // If we have a last_Java_sp, then the SIGPROF signal caught us
     // right when we were transitioning from _thread_in_Java to a new
     // JavaThreadState. We use last_Java_sp instead of the sp from
     // the ucontext since it should be more reliable.
+
     if (jt->has_last_Java_frame()) {
       ret_sp = jt->last_Java_sp();
+      frame ret_frame2(ret_sp, frame::unpatchable, addr.pc());
+      if (ret_frame2.safe_for_sender(jt)) {
+        *fr_addr = ret_frame2;
+        return true;
+      }
     }
-    // Implied else: we don't have a last_Java_sp so we use what we
-    // got from the ucontext.
 
-    frame ret_frame(ret_sp, frame::unpatchable, addr.pc());
-    if (!ret_frame.safe_for_sender(jt)) {
-      // nothing else to try if the frame isn't good
-      return false;
-    }
+    // This is the best we can do. We will only be able to decode the top frame
+
     *fr_addr = ret_frame;
     return true;
   }
@@ -105,17 +130,13 @@
   if (jt->has_last_Java_frame()) {
     assert(!jt->frame_anchor()->walkable(), "case covered above");
 
-    if (jt->thread_state() == _thread_in_native) {
-      frame ret_frame(jt->last_Java_sp(), frame::unpatchable, addr.pc());
-      if (!ret_frame.safe_for_sender(jt)) {
-        // nothing else to try if the frame isn't good
-        return false;
-      }
-      *fr_addr = ret_frame;
-      return true;
-    }
+    frame ret_frame(jt->last_Java_sp(), frame::unpatchable, addr.pc());
+    *fr_addr = ret_frame;
+    return true;
   }
 
-  // nothing else to try
-  return false;
+  // nothing else to try but what we found initially
+
+  *fr_addr = ret_frame;
+  return true;
 }
--- a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp	Fri Apr 11 09:56:35 2008 -0400
@@ -212,7 +212,8 @@
                 CAST_FROM_FN_PTR(address, os::current_frame));
   if (os::is_first_C_frame(&myframe)) {
     // stack is not walkable
-    return frame(NULL, NULL, NULL);
+    frame ret; // This will be a null useless frame
+    return ret;
   } else {
     return os::get_sender_for_C_frame(&myframe);
   }
--- a/hotspot/src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp	Fri Apr 11 09:56:35 2008 -0400
@@ -32,49 +32,53 @@
 
   assert(Thread::current() == this, "caller must be current thread");
   assert(this->is_Java_thread(), "must be JavaThread");
-
   JavaThread* jt = (JavaThread *)this;
 
-  // If we have a last_Java_frame, then we should use it even if
-  // isInJava == true.  It should be more reliable than ucontext info.
+  // last_Java_frame is always walkable and safe use it if we have it
+
   if (jt->has_last_Java_frame()) {
     *fr_addr = jt->pd_last_frame();
     return true;
   }
 
-  // At this point, we don't have a last_Java_frame, so
-  // we try to glean some information out of the ucontext
-  // if we were running Java code when SIGPROF came in.
-  if (isInJava) {
-    ucontext_t* uc = (ucontext_t*) ucontext;
+  ucontext_t* uc = (ucontext_t*) ucontext;
 
-    intptr_t* ret_fp;
-    intptr_t* ret_sp;
-    ExtendedPC addr = os::Solaris::fetch_frame_from_ucontext(this, uc,
-      &ret_sp, &ret_fp);
-    if (addr.pc() == NULL || ret_sp == NULL ) {
-      // ucontext wasn't useful
-      return false;
-    }
+  // We always want to use the initial frame we create from the ucontext as
+  // it certainly signals where we currently are. However that frame may not
+  // be safe for calling sender. In that case if we have a last_Java_frame
+  // then the forte walker will switch to that frame as the virtual sender
+  // for the frame we create here which is not sender safe.
 
-    frame ret_frame(ret_sp, ret_fp, addr.pc());
-    if (!ret_frame.safe_for_sender(jt)) {
-#ifdef COMPILER2
-      frame ret_frame2(ret_sp, NULL, addr.pc());
-      if (!ret_frame2.safe_for_sender(jt)) {
-        // nothing else to try if the frame isn't good
-        return false;
-      }
-      ret_frame = ret_frame2;
-#else
-      // nothing else to try if the frame isn't good
-      return false;
-#endif /* COMPILER2 */
-    }
-    *fr_addr = ret_frame;
-    return true;
+  intptr_t* ret_fp;
+  intptr_t* ret_sp;
+  ExtendedPC addr = os::Solaris::fetch_frame_from_ucontext(this, uc, &ret_sp, &ret_fp);
+
+  // Something would really have to be screwed up to get a NULL pc
+
+  if (addr.pc() == NULL ) {
+    assert(false, "NULL pc from signal handler!");
+    return false;
+
   }
 
-  // nothing else to try
-  return false;
+  // If sp and fp are nonsense just leave them out
+
+  if ((address)ret_sp >= jt->stack_base() ||
+      (address)ret_sp < jt->stack_base() - jt->stack_size() ) {
+
+      ret_sp = NULL;
+      ret_fp = NULL;
+  } else {
+
+    // sp is reasonable is fp reasonable?
+    if ( (address)ret_fp >= jt->stack_base() || ret_fp < ret_sp) {
+      ret_fp = NULL;
+    }
+  }
+
+  frame ret_frame(ret_sp, ret_fp, addr.pc());
+
+  *fr_addr = ret_frame;
+  return true;
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/tools/hsdis/Makefile	Fri Apr 11 09:56:35 2008 -0400
@@ -0,0 +1,135 @@
+#
+# Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#  
+#
+
+# Single gnu makefile for solaris, linux and windows (windows requires mks or
+# cygwin).
+
+ifeq            ($(BINUTILS),)
+# Pop all the way out of the workspace to look for binutils.
+# ...You probably want to override this setting.
+BINUTILS	= $(shell cd ../../../../..;pwd)/binutils-2.17-$(LIBARCH)
+endif
+
+# Default arch; it is changed below as needed.
+ARCH		= i386
+OS		= $(shell uname)
+
+CPPFLAGS	+= -I$(BINUTILS)/include -I$(BINUTILS)/bfd
+CPPFLAGS	+= -DHOTSPOT_LIB_ARCH=\"$(LIBARCH)\" -DLIBARCH_$(LIBARCH)
+CPPFLAGS	+= -DHOTSPOT_OS=\"$(OS)\" -DOS_$(OS)
+
+## OS = SunOS ##
+ifeq		($(OS),SunOS)
+ARCH    	= $(shell uname -p)
+OS		= solaris
+CC 		= cc
+CCFLAGS		+= -Kpic -g
+CCFLAGS/amd64   += -xarch=amd64
+CCFLAGS/sparcv9 += -xarch=v9
+CCFLAGS		+= $(CCFLAGS/$(LIBARCH))
+DLDFLAGS	+= -G
+OUTFLAGS	+= -o $@
+LIB_EXT		= .so
+else
+## OS = Linux ##
+ifeq		($(OS),Linux)
+CPU             = $(shell uname -m)
+ifeq		($(CPU),ia64)
+ARCH    	= ia64
+else
+ifeq		($(CPU),x86_64)
+CCFLAGS		+= -fPIC
+endif   # x86_64
+endif   # ia64
+OS		= linux
+CC 		= gcc
+CCFLAGS		+= -O
+DLDFLAGS	+= -shared
+OUTFLAGS	+= -o $@
+LIB_EXT		= .so
+CPPFLAGS	+= -Iinclude -Iinclude/$(OS)_$(ARCH)/
+## OS = Windows ##
+else   # !SunOS, !Linux => Windows
+OS		= win
+CC		= cl
+#CPPFLAGS	+= /D"WIN32" /D"_WINDOWS" /D"DEBUG" /D"NDEBUG"
+CCFLAGS		+=  /nologo /MD /W3 /WX /O2 /Fo$(@:.dll=.obj) /Gi-
+CCFLAGS		+= -Iinclude -Iinclude/gnu -Iinclude/$(OS)_$(ARCH)
+CCFLAGS		+= /D"HOTSPOT_LIB_ARCH=\"$(LIBARCH)\""
+DLDFLAGS	+= /dll /subsystem:windows /incremental:no \
+			/export:decode_instruction
+OUTFLAGS	+= /link /out:$@
+LIB_EXT		= .dll
+endif	# Linux
+endif	# SunOS
+
+LIBARCH		= $(ARCH)
+ifdef		LP64
+LIBARCH64/sparc	= sparcv9
+LIBARCH64/i386	= amd64
+LIBARCH64	= $(LIBARCH64/$(ARCH))
+ifneq		($(LIBARCH64),)
+LIBARCH		= $(LIBARCH64)
+endif   # LIBARCH64/$(ARCH)
+endif   # LP64
+
+TARGET_DIR	= bin/$(OS)
+TARGET		= $(TARGET_DIR)/hsdis-$(LIBARCH)$(LIB_EXT)
+
+SOURCE		= hsdis.c
+
+LIBRARIES =	$(BINUTILS)/bfd/libbfd.a \
+		$(BINUTILS)/opcodes/libopcodes.a \
+		$(BINUTILS)/libiberty/libiberty.a
+
+DEMO_TARGET	= $(TARGET_DIR)/hsdis-demo-$(LIBARCH)
+DEMO_SOURCE	= hsdis-demo.c
+
+.PHONY:  all clean demo both
+
+all:  $(TARGET) demo
+
+both: all all64
+
+%64:
+	$(MAKE) LP64=1 ${@:%64=%}
+
+demo: $(TARGET) $(DEMO_TARGET)
+
+$(LIBRARIES):
+	@echo "*** Please build binutils first; see ./README: ***"
+	@sed < ./README '1,/__________/d' | head -20
+	@echo "..."; exit 1
+
+$(TARGET): $(SOURCE) $(LIBS) $(LIBRARIES) $(TARGET_DIR)
+	$(CC) $(OUTFLAGS) $(CPPFLAGS) $(CCFLAGS) $(SOURCE) $(DLDFLAGS) $(LIBRARIES)
+
+$(DEMO_TARGET): $(DEMO_SOURCE) $(TARGET) $(TARGET_DIR)
+	$(CC) $(OUTFLAGS) $(CPPFLAGS) $(CCFLAGS) $(DEMO_SOURCE) $(LDFLAGS)
+
+$(TARGET_DIR):
+	[ -d $@ ] || mkdir -p $@
+
+clean:
+	rm -rf $(TARGET_DIR)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/tools/hsdis/README	Fri Apr 11 09:56:35 2008 -0400
@@ -0,0 +1,95 @@
+Copyright (c) 2008 Sun Microsystems, Inc.  All Rights Reserved.
+DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+  
+This code is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 2 only, as
+published by the Free Software Foundation.
+  
+This code is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+version 2 for more details (a copy is included in the LICENSE file that
+accompanied this code).
+ 
+You should have received a copy of the GNU General Public License version
+2 along with this work; if not, write to the Free Software Foundation,
+Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+  
+Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+CA 95054 USA or visit www.sun.com if you need additional information or
+have any questions.
+
+________________________________________________________________________
+
+'hsdis':  A HotSpot plugin for disassembling dynamically generated code.
+
+The files in this directory (Makefile, hsdis.[ch], hsdis-demo.c)
+are built independently of the HotSpot JVM.
+
+To use the plugin with a JVM, you need a new version that can load it.
+If the product mode of your JVM does not accept -XX:+PrintAssembly,
+you do not have a version that is new enough.
+
+* Building
+
+To build this project you need a build of Gnu binutils to link against.
+It is known to work with binutils 2.17.
+
+The makefile looks for this build in $BINUTILS, or (if that is not set),
+in  .../binutils-2.17-$LIBARCH, where LIBARCH (as in HotSpot) is one of
+the jre subdirectory keywords i386, amd64, sparc, sparcv9, etc.
+
+To build Gnu binutils, first download a copy of the software:
+  http://directory.fsf.org/project/binutils/
+
+Unpack the binutils tarball into an empty directory:
+  chdir ../../../../..
+  tar -xzf - < ../binutils-2.17.tar.gz
+  mv binutils-2.17 binutils-2.17-i386  #or binutils-2.17-sparc
+  cd binutils-2.17-i386
+
+From inside that directory, run configure and make:
+  ( export CFLAGS='-fPIC'
+    ./configure i386-pc-elf )
+  gnumake
+
+(Leave out or change the argument to configure if not on an i386 system.)
+
+Next, untar again into another empty directory for the LP64 version:
+  chdir ..
+  tar -xzf - < ../binutils-2.17.tar.gz
+  mv binutils-2.17 binutils-2.17-amd64  #or binutils-2.17-sparcv9
+  cd binutils-2.17-amd64
+
+From inside that directory, run configure for LP64 and make:
+  ( export ac_cv_c_bigendian=no CFLAGS='-m64 -fPIC' LDFLAGS=-m64
+    ./configure amd64-pc-elf )
+  gnumake
+
+The -fPIC option is needed because the generated code will be
+linked into the hsdid-$LIBARCH.so binary.  If you miss the
+option, the JVM will fail to load the disassembler.
+
+You probably want two builds, one for 32 and one for 64 bits.
+To build the 64-bit variation of a platforn, add LP64=1 to
+the make command line for hsdis.
+
+So, go back to the hsdis project and build:
+  chdir .../hsdis
+  gnumake
+  gnumake LP64=1
+
+* Installing
+
+Products are named like bin/$OS/hsdis-$LIBARCH.so.
+You can install them on your LD_LIBRARY_PATH,
+or inside of your JRE next to $LIBARCH/libjvm.so.
+
+Now test:
+  export LD_LIBRARY_PATH .../hsdis/bin/solaris:$LD_LIBRARY_PATH
+  dargs='-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly'
+  dargs=$dargs' -XX:PrintAssemblyOptions=hsdis-print-bytes'
+  java $dargs -Xbatch CompileCommand=print,*String.hashCode HelloWorld
+
+If the product mode of the JVM does not accept -XX:+PrintAssembly,
+you do not have a version new enough to use the hsdis plugin.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/tools/hsdis/hsdis-demo.c	Fri Apr 11 09:56:35 2008 -0400
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+/* hsdis-demo.c -- dump a range of addresses as native instructions
+   This demonstrates the protocol required by the HotSpot PrintAssembly option.
+*/
+
+#include "hsdis.h"
+
+#include "stdio.h"
+#include "stdlib.h"
+#include "string.h"
+
+void greet(const char*);
+void disassemble(void*, void*);
+void end_of_file();
+
+const char* options = NULL;
+int         raw     = 0;
+int         xml     = 0;
+
+int main(int ac, char** av) {
+  int greeted = 0;
+  int i;
+  for (i = 1; i < ac; i++) {
+    const char* arg = av[i];
+    if (arg[0] == '-') {
+      if (!strcmp(arg, "-xml"))
+        xml ^= 1;
+      else if (!strcmp(arg, "-raw"))
+        raw ^= 1;
+      else if (!strncmp(arg, "-options=", 9))
+        options = arg+9;
+      else
+        { printf("Usage: %s [-xml] [name...]\n"); exit(2); }
+      continue;
+    }
+    greet(arg);
+    greeted = 1;
+  }
+  if (!greeted)
+    greet("world");
+  printf("...And now for something completely different:\n");
+  disassemble((void*) &main, (void*) &end_of_file);
+  printf("Cheers!\n");
+}
+
+void greet(const char* whom) {
+  printf("Hello, %s!\n", whom);
+}
+
+void end_of_file() { }
+
+/* don't disassemble after this point... */
+
+#include "dlfcn.h"
+
+#ifdef HOTSPOT_LIB_ARCH
+#define LIBARCH HOTSPOT_LIB_ARCH
+#endif
+#ifdef HOTSPOT_OS
+#define OS HOTSPOT_OS
+#endif
+
+#define DECODE_INSTRUCTIONS_NAME "decode_instructions"
+#define HSDIS_NAME               "hsdis"
+static void* decode_instructions_pv = 0;
+static const char* hsdis_path[] = {
+  HSDIS_NAME".so",
+#ifdef OS
+  "bin/"OS"/"HSDIS_NAME".so",
+#endif
+#ifdef LIBARCH
+  HSDIS_NAME"-"LIBARCH".so",
+#ifdef OS
+  "bin/"OS"/"HSDIS_NAME"-"LIBARCH".so",
+#endif
+#endif
+  NULL
+};
+
+static const char* load_decode_instructions() {
+  void* dllib = NULL;
+  const char* *next_in_path = hsdis_path;
+  while (1) {
+    decode_instructions_pv = dlsym(dllib, DECODE_INSTRUCTIONS_NAME);
+    if (decode_instructions_pv != NULL)
+      return NULL;
+    if (dllib != NULL)
+      return "plugin does not defined "DECODE_INSTRUCTIONS_NAME;
+    for (dllib = NULL; dllib == NULL; ) {
+      const char* next_lib = (*next_in_path++);
+      if (next_lib == NULL)
+        return "cannot find plugin "HSDIS_NAME".so";
+      dllib = dlopen(next_lib, RTLD_LAZY);
+    }
+  }
+}
+
+
+static const char* lookup(void* addr) {
+#define CHECK_NAME(fn) \
+  if (addr == (void*) &fn)  return #fn;
+
+  CHECK_NAME(main);
+  CHECK_NAME(greet);
+  return NULL;
+}
+
+/* does the event match the tag, followed by a null, space, or slash? */
+#define MATCH(event, tag) \
+  (!strncmp(event, tag, sizeof(tag)-1) && \
+   (!event[sizeof(tag)-1] || strchr(" /", event[sizeof(tag)-1])))
+
+
+static const char event_cookie[] = "event_cookie"; /* demo placeholder */
+static void* handle_event(void* cookie, const char* event, void* arg) {
+#define NS_DEMO "demo:"
+  if (cookie != event_cookie)
+    printf("*** bad event cookie %p != %p\n", cookie, event_cookie);
+
+  if (xml) {
+    /* We could almost do a printf(event, arg),
+       but for the sake of a better demo,
+       we dress the result up as valid XML.
+    */
+    const char* fmt = strchr(event, ' ');
+    int evlen = (fmt ? fmt - event : strlen(event));
+    if (!fmt) {
+      if (event[0] != '/') {
+        printf("<"NS_DEMO"%.*s>", evlen, event);
+      } else {
+        printf("</"NS_DEMO"%.*s>", evlen-1, event+1);
+      }
+    } else {
+      if (event[0] != '/') {
+        printf("<"NS_DEMO"%.*s", evlen, event);
+        printf(fmt, arg);
+        printf(">");
+      } else {
+        printf("<"NS_DEMO"%.*s_done", evlen-1, event+1);
+        printf(fmt, arg);
+        printf("/></"NS_DEMO"%.*s>", evlen-1, event+1);
+      }
+    }
+  }
+
+  if (MATCH(event, "insn")) {
+    const char* name = lookup(arg);
+    if (name)  printf("%s:\n", name);
+
+    /* basic action for <insn>: */
+    printf(" %p\t", arg);
+
+  } else if (MATCH(event, "/insn")) {
+    /* basic action for </insn>:
+       (none, plugin puts the newline for us
+    */
+
+  } else if (MATCH(event, "mach")) {
+    printf("Decoding for CPU '%s'\n", (char*) arg);
+
+  } else if (MATCH(event, "addr")) {
+    /* basic action for <addr/>: */
+    const char* name = lookup(arg);
+    if (name) {
+      printf("&%s (%p)", name, arg);
+      /* return non-null to notify hsdis not to print the addr */
+      return arg;
+    }
+  }
+
+  /* null return is always safe; can mean "I ignored it" */
+  return NULL;
+}
+
+#define fprintf_callback \
+  (decode_instructions_printf_callback_ftype)&fprintf
+
+void disassemble(void* from, void* to) {
+  const char* err = load_decode_instructions();
+  if (err != NULL) {
+    printf("%s: %s\n", err, dlerror());
+    exit(1);
+  }
+  printf("Decoding from %p to %p...\n", from, to);
+  decode_instructions_ftype decode_instructions
+    = (decode_instructions_ftype) decode_instructions_pv;
+  void* res;
+  if (raw && xml) {
+    res = (*decode_instructions)(from, to, NULL, stdout, NULL, stdout, options);
+  } else if (raw) {
+    res = (*decode_instructions)(from, to, NULL, NULL, NULL, stdout, options);
+  } else {
+    res = (*decode_instructions)(from, to,
+                                 handle_event, (void*) event_cookie,
+                                 fprintf_callback, stdout,
+                                 options);
+  }
+  if (res != to)
+    printf("*** Result was %p!\n", res);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/tools/hsdis/hsdis.c	Fri Apr 11 09:56:35 2008 -0400
@@ -0,0 +1,499 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+/* hsdis.c -- dump a range of addresses as native instructions
+   This implements the plugin protocol required by the
+   HotSpot PrintAssembly option.
+*/
+
+#include "hsdis.h"
+
+#include <sysdep.h>
+#include <libiberty.h>
+#include <bfd.h>
+#include <dis-asm.h>
+
+#ifndef bool
+#define bool int
+#define true 1
+#define false 0
+#endif /*bool*/
+
+/* short names for stuff in hsdis.h */
+typedef decode_instructions_event_callback_ftype  event_callback_t;
+typedef decode_instructions_printf_callback_ftype printf_callback_t;
+
+/* disassemble_info.application_data object */
+struct hsdis_app_data {
+  /* the arguments to decode_instructions */
+  uintptr_t start; uintptr_t end;
+  event_callback_t  event_callback;  void* event_stream;
+  printf_callback_t printf_callback; void* printf_stream;
+  bool losing;
+
+  /* the architecture being disassembled */
+  const char* arch_name;
+  const bfd_arch_info_type* arch_info;
+
+  /* the disassembler we are going to use: */
+  disassembler_ftype      dfn;
+  struct disassemble_info dinfo; /* the actual struct! */
+
+  char mach_option[64];
+  char insn_options[256];
+};
+
+#define DECL_APP_DATA(dinfo) \
+  struct hsdis_app_data* app_data = (struct hsdis_app_data*) (dinfo)->application_data
+
+#define DECL_EVENT_CALLBACK(app_data) \
+  event_callback_t  event_callback = (app_data)->event_callback; \
+  void*             event_stream   = (app_data)->event_stream
+
+#define DECL_PRINTF_CALLBACK(app_data) \
+  printf_callback_t  printf_callback = (app_data)->printf_callback; \
+  void*              printf_stream   = (app_data)->printf_stream
+
+
+static void print_help(struct hsdis_app_data* app_data,
+                       const char* msg, const char* arg);
+static void setup_app_data(struct hsdis_app_data* app_data,
+                           const char* options);
+static const char* format_insn_close(const char* close,
+                                     disassemble_info* dinfo,
+                                     char* buf, size_t bufsize);
+
+void*
+#ifdef DLL_ENTRY
+  DLL_ENTRY
+#endif
+decode_instructions(void* start_pv, void* end_pv,
+                    event_callback_t  event_callback_arg,  void* event_stream_arg,
+                    printf_callback_t printf_callback_arg, void* printf_stream_arg,
+                    const char* options) {
+  struct hsdis_app_data app_data;
+  memset(&app_data, 0, sizeof(app_data));
+  app_data.start = (uintptr_t) start_pv;
+  app_data.end   = (uintptr_t) end_pv;
+  app_data.event_callback  = event_callback_arg;
+  app_data.event_stream    = event_stream_arg;
+  app_data.printf_callback = printf_callback_arg;
+  app_data.printf_stream   = printf_stream_arg;
+
+  setup_app_data(&app_data, options);
+  char buf[128];
+
+  {
+    /* now reload everything from app_data: */
+    DECL_EVENT_CALLBACK(&app_data);
+    DECL_PRINTF_CALLBACK(&app_data);
+    uintptr_t start = app_data.start;
+    uintptr_t end   = app_data.end;
+    uintptr_t p     = start;
+
+    (*event_callback)(event_stream, "insns", (void*)start);
+
+    (*event_callback)(event_stream, "mach name='%s'",
+                      (void*) app_data.arch_info->printable_name);
+    if (app_data.dinfo.bytes_per_line != 0) {
+      (*event_callback)(event_stream, "format bytes-per-line='%p'/",
+                        (void*)(intptr_t) app_data.dinfo.bytes_per_line);
+    }
+
+    while (p < end && !app_data.losing) {
+      (*event_callback)(event_stream, "insn", (void*) p);
+
+      /* reset certain state, so we can read it with confidence */
+      app_data.dinfo.insn_info_valid    = 0;
+      app_data.dinfo.branch_delay_insns = 0;
+      app_data.dinfo.data_size          = 0;
+      app_data.dinfo.insn_type          = 0;
+
+      int size = (*app_data.dfn)((bfd_vma) p, &app_data.dinfo);
+
+      if (size > 0)  p += size;
+      else           app_data.losing = true;
+
+      const char* insn_close = format_insn_close("/insn", &app_data.dinfo,
+                                                 buf, sizeof(buf));
+      (*event_callback)(event_stream, insn_close, (void*) p);
+
+      /* follow each complete insn by a nice newline */
+      (*printf_callback)(printf_stream, "\n");
+    }
+
+    (*event_callback)(event_stream, "/insns", (void*) p);
+    return (void*) p;
+  }
+}
+
+/* take the address of the function, for luck, and also test the typedef: */
+const decode_instructions_ftype decode_instructions_address = &decode_instructions;
+
+static const char* format_insn_close(const char* close,
+                                     disassemble_info* dinfo,
+                                     char* buf, size_t bufsize) {
+  if (!dinfo->insn_info_valid)
+    return close;
+  enum dis_insn_type itype = dinfo->insn_type;
+  int dsize = dinfo->data_size, delays = dinfo->branch_delay_insns;
+  if ((itype == dis_nonbranch && (dsize | delays) == 0)
+      || (strlen(close) + 3*20 > bufsize))
+    return close;
+
+  const char* type = "unknown";
+  switch (itype) {
+  case dis_nonbranch:   type = NULL;         break;
+  case dis_branch:      type = "branch";     break;
+  case dis_condbranch:  type = "condbranch"; break;
+  case dis_jsr:         type = "jsr";        break;
+  case dis_condjsr:     type = "condjsr";    break;
+  case dis_dref:        type = "dref";       break;
+  case dis_dref2:       type = "dref2";      break;
+  }
+
+  strcpy(buf, close);
+  char* p = buf;
+  if (type)    sprintf(p += strlen(p), " type='%s'", type);
+  if (dsize)   sprintf(p += strlen(p), " dsize='%d'", dsize);
+  if (delays)  sprintf(p += strlen(p), " delay='%d'", delays);
+  return buf;
+}
+
+/* handler functions */
+
+static int
+hsdis_read_memory_func(bfd_vma memaddr,
+                       bfd_byte* myaddr,
+                       unsigned int length,
+                       struct disassemble_info* dinfo) {
+  uintptr_t memaddr_p = (uintptr_t) memaddr;
+  DECL_APP_DATA(dinfo);
+  if (memaddr_p + length > app_data->end) {
+    /* read is out of bounds */
+    return EIO;
+  } else {
+    memcpy(myaddr, (bfd_byte*) memaddr_p, length);
+    return 0;
+  }
+}
+
+static void
+hsdis_print_address_func(bfd_vma vma, struct disassemble_info* dinfo) {
+  /* the actual value to print: */
+  void* addr_value = (void*) (uintptr_t) vma;
+  DECL_APP_DATA(dinfo);
+  DECL_EVENT_CALLBACK(app_data);
+
+  /* issue the event: */
+  void* result =
+    (*event_callback)(event_stream, "addr/", addr_value);
+  if (result == NULL) {
+    /* event declined */
+    generic_print_address(vma, dinfo);
+  }
+}
+
+
+/* configuration */
+
+static void set_optional_callbacks(struct hsdis_app_data* app_data);
+static void parse_caller_options(struct hsdis_app_data* app_data,
+                                 const char* caller_options);
+static const char* native_arch_name();
+static enum bfd_endian native_endian();
+static const bfd_arch_info_type* find_arch_info(const char* arch_nane);
+static bfd* get_native_bfd(const bfd_arch_info_type* arch_info,
+                           /* to avoid malloc: */
+                           bfd* empty_bfd, bfd_target* empty_xvec);
+static void init_disassemble_info_from_bfd(struct disassemble_info* dinfo,
+                                           void *stream,
+                                           fprintf_ftype fprintf_func,
+                                           bfd* bfd,
+                                           char* disassembler_options);
+static void parse_fake_insn(disassembler_ftype dfn,
+                            struct disassemble_info* dinfo);
+
+static void setup_app_data(struct hsdis_app_data* app_data,
+                           const char* caller_options) {
+  /* Make reasonable defaults for null callbacks.
+     A non-null stream for a null callback is assumed to be a FILE* for output.
+     Events are rendered as XML.
+  */
+  set_optional_callbacks(app_data);
+
+  /* Look into caller_options for anything interesting. */
+  if (caller_options != NULL)
+    parse_caller_options(app_data, caller_options);
+
+  /* Discover which architecture we are going to disassemble. */
+  app_data->arch_name = &app_data->mach_option[0];
+  if (app_data->arch_name[0] == '\0')
+    app_data->arch_name = native_arch_name();
+  app_data->arch_info = find_arch_info(app_data->arch_name);
+
+  /* Make a fake bfd to hold the arch. and byteorder info. */
+  struct {
+    bfd_target empty_xvec;
+    bfd        empty_bfd;
+  } buf;
+  bfd* native_bfd = get_native_bfd(app_data->arch_info,
+                                   /* to avoid malloc: */
+                                   &buf.empty_bfd, &buf.empty_xvec);
+  init_disassemble_info_from_bfd(&app_data->dinfo,
+                                 app_data->printf_stream,
+                                 app_data->printf_callback,
+                                 native_bfd,
+                                 app_data->insn_options);
+
+  /* Finish linking together the various callback blocks. */
+  app_data->dinfo.application_data = (void*) app_data;
+  app_data->dfn = disassembler(native_bfd);
+  app_data->dinfo.print_address_func = hsdis_print_address_func;
+  app_data->dinfo.read_memory_func = hsdis_read_memory_func;
+
+  if (app_data->dfn == NULL) {
+    const char* bad = app_data->arch_name;
+    static bool complained;
+    if (bad == &app_data->mach_option[0])
+      print_help(app_data, "bad mach=%s", bad);
+    else if (!complained)
+      print_help(app_data, "bad native mach=%s; please port hsdis to this platform", bad);
+    complained = true;
+    /* must bail out */
+    app_data->losing = true;
+    return;
+  }
+
+  parse_fake_insn(app_data->dfn, &app_data->dinfo);
+}
+
+
+/* ignore all events, return a null */
+static void* null_event_callback(void* ignore_stream, const char* ignore_event, void* arg) {
+  return NULL;
+}
+
+/* print all events as XML markup */
+static void* xml_event_callback(void* stream, const char* event, void* arg) {
+  FILE* fp = (FILE*) stream;
+#define NS_PFX "dis:"
+  if (event[0] != '/') {
+    /* issue the tag, with or without a formatted argument */
+    fprintf(fp, "<"NS_PFX);
+    fprintf(fp, event, arg);
+    fprintf(fp, ">");
+  } else {
+    ++event;                    /* skip slash */
+    const char* argp = strchr(event, ' ');
+    if (argp == NULL) {
+      /* no arguments; just issue the closing tag */
+      fprintf(fp, "</"NS_PFX"%s>", event);
+    } else {
+      /* split out the closing attributes as <dis:foo_done attr='val'/> */
+      int event_prefix = (argp - event);
+      fprintf(fp, "<"NS_PFX"%.*s_done", event_prefix, event);
+      fprintf(fp, argp, arg);
+      fprintf(fp, "/></"NS_PFX"%.*s>", event_prefix, event);
+    }
+  }
+  return NULL;
+}
+
+static void set_optional_callbacks(struct hsdis_app_data* app_data) {
+  if (app_data->printf_callback == NULL) {
+    int (*fprintf_callback)(FILE*, const char*, ...) = &fprintf;
+    FILE* fprintf_stream = stdout;
+    app_data->printf_callback = (printf_callback_t) fprintf_callback;
+    if (app_data->printf_stream == NULL)
+      app_data->printf_stream   = (void*)           fprintf_stream;
+  }
+  if (app_data->event_callback == NULL) {
+    if (app_data->event_stream == NULL)
+      app_data->event_callback = &null_event_callback;
+    else
+      app_data->event_callback = &xml_event_callback;
+  }
+
+}
+
+static void parse_caller_options(struct hsdis_app_data* app_data, const char* caller_options) {
+  char* iop_base = app_data->insn_options;
+  char* iop_limit = iop_base + sizeof(app_data->insn_options) - 1;
+  char* iop = iop_base;
+  const char* p;
+  for (p = caller_options; p != NULL; ) {
+    const char* q = strchr(p, ',');
+    size_t plen = (q == NULL) ? strlen(p) : ((q++) - p);
+    if (plen == 4 && strncmp(p, "help", plen) == 0) {
+      print_help(app_data, NULL, NULL);
+    } else if (plen >= 5 && strncmp(p, "mach=", 5) == 0) {
+      char*  mach_option = app_data->mach_option;
+      size_t mach_size   = sizeof(app_data->mach_option);
+      mach_size -= 1;           /*leave room for the null*/
+      if (plen > mach_size)  plen = mach_size;
+      strncpy(mach_option, p, plen);
+      mach_option[plen] = '\0';
+    } else if (plen > 6 && strncmp(p, "hsdis-", 6)) {
+      // do not pass these to the next level
+    } else {
+      /* just copy it; {i386,sparc}-dis.c might like to see it  */
+      if (iop > iop_base && iop < iop_limit)  (*iop++) = ',';
+      if (iop + plen > iop_limit)
+        plen = iop_limit - iop;
+      strncpy(iop, p, plen);
+      iop += plen;
+    }
+    p = q;
+  }
+}
+
+static void print_help(struct hsdis_app_data* app_data,
+                       const char* msg, const char* arg) {
+  DECL_PRINTF_CALLBACK(app_data);
+  if (msg != NULL) {
+    (*printf_callback)(printf_stream, "hsdis: ");
+    (*printf_callback)(printf_stream, msg, arg);
+    (*printf_callback)(printf_stream, "\n");
+  }
+  (*printf_callback)(printf_stream, "hsdis output options:\n");
+  if (printf_callback == (printf_callback_t) &fprintf)
+    disassembler_usage((FILE*) printf_stream);
+  else
+    disassembler_usage(stderr); /* better than nothing */
+  (*printf_callback)(printf_stream, "  mach=<arch>   select disassembly mode\n");
+#if defined(LIBARCH_i386) || defined(LIBARCH_amd64)
+  (*printf_callback)(printf_stream, "  mach=i386     select 32-bit mode\n");
+  (*printf_callback)(printf_stream, "  mach=x86-64   select 64-bit mode\n");
+  (*printf_callback)(printf_stream, "  suffix        always print instruction suffix\n");
+#endif
+  (*printf_callback)(printf_stream, "  help          print this message\n");
+}
+
+
+/* low-level bfd and arch stuff that binutils doesn't do for us */
+
+static const bfd_arch_info_type* find_arch_info(const char* arch_name) {
+  const bfd_arch_info_type* arch_info = bfd_scan_arch(arch_name);
+  if (arch_info == NULL) {
+    extern const bfd_arch_info_type bfd_default_arch_struct;
+    arch_info = &bfd_default_arch_struct;
+  }
+  return arch_info;
+}
+
+static const char* native_arch_name() {
+  const char* res = HOTSPOT_LIB_ARCH;
+#ifdef LIBARCH_amd64
+    res = "i386:x86-64";
+#endif
+#ifdef LIBARCH_sparc
+    res = "sparc:v8plusb";
+#endif
+#ifdef LIBARCH_sparc
+    res = "sparc:v8plusb";
+#endif
+#ifdef LIBARCH_sparcv9
+    res = "sparc:v9b";
+#endif
+  if (res == NULL)
+    res = "HOTSPOT_LIB_ARCH is not set in Makefile!";
+  return res;
+}
+
+static enum bfd_endian native_endian() {
+  int32_t endian_test = 'x';
+  if (*(const char*) &endian_test == 'x')
+    return BFD_ENDIAN_LITTLE;
+  else
+    return BFD_ENDIAN_BIG;
+}
+
+static bfd* get_native_bfd(const bfd_arch_info_type* arch_info,
+                           bfd* empty_bfd, bfd_target* empty_xvec) {
+  memset(empty_bfd,  0, sizeof(*empty_bfd));
+  memset(empty_xvec, 0, sizeof(*empty_xvec));
+  empty_xvec->flavour = bfd_target_unknown_flavour;
+  empty_xvec->byteorder = native_endian();
+  empty_bfd->xvec = empty_xvec;
+  empty_bfd->arch_info = arch_info;
+  return empty_bfd;
+}
+
+static int read_zero_data_only(bfd_vma ignore_p,
+                               bfd_byte* myaddr, unsigned int length,
+                               struct disassemble_info *ignore_info) {
+  memset(myaddr, 0, length);
+  return 0;
+}
+static int print_to_dev_null(void* ignore_stream, const char* ignore_format, ...) {
+  return 0;
+}
+
+/* Prime the pump by running the selected disassembler on a null input.
+   This forces the machine-specific disassembler to divulge invariant
+   information like bytes_per_line.
+ */
+static void parse_fake_insn(disassembler_ftype dfn,
+                            struct disassemble_info* dinfo) {
+  typedef int (*read_memory_ftype)
+    (bfd_vma memaddr, bfd_byte *myaddr, unsigned int length,
+     struct disassemble_info *info);
+  read_memory_ftype read_memory_func = dinfo->read_memory_func;
+  fprintf_ftype     fprintf_func     = dinfo->fprintf_func;
+
+  dinfo->read_memory_func = &read_zero_data_only;
+  dinfo->fprintf_func     = &print_to_dev_null;
+  (*dfn)(0, dinfo);
+
+  // put it back:
+  dinfo->read_memory_func = read_memory_func;
+  dinfo->fprintf_func     = fprintf_func;
+}
+
+static void init_disassemble_info_from_bfd(struct disassemble_info* dinfo,
+                                           void *stream,
+                                           fprintf_ftype fprintf_func,
+                                           bfd* abfd,
+                                           char* disassembler_options) {
+  init_disassemble_info(dinfo, stream, fprintf_func);
+
+  dinfo->flavour = bfd_get_flavour(abfd);
+  dinfo->arch = bfd_get_arch(abfd);
+  dinfo->mach = bfd_get_mach(abfd);
+  dinfo->disassembler_options = disassembler_options;
+  dinfo->octets_per_byte = bfd_octets_per_byte (abfd);
+  dinfo->skip_zeroes = sizeof(void*) * 2;
+  dinfo->skip_zeroes_at_end = sizeof(void*)-1;
+  dinfo->disassembler_needs_relocs = FALSE;
+
+  if (bfd_big_endian(abfd))
+    dinfo->display_endian = dinfo->endian = BFD_ENDIAN_BIG;
+  else if (bfd_little_endian(abfd))
+    dinfo->display_endian = dinfo->endian = BFD_ENDIAN_LITTLE;
+  else
+    dinfo->endian = native_endian();
+
+  disassemble_init_for_target(dinfo);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/tools/hsdis/hsdis.h	Fri Apr 11 09:56:35 2008 -0400
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+/* decode_instructions -- dump a range of addresses as native instructions
+   This implements the protocol required by the HotSpot PrintAssembly option.
+
+   The starting and ending addresses are within the current process's address space.
+
+   The option string, if not empty, is interpreted by the disassembler implementation.
+
+   The printf callback is 'fprintf' or any other workalike.
+   It is called as (*printf_callback)(printf_stream, "some format...", some, format, args).
+
+   The event callback receives an event tag (a string) and an argument (a void*).
+   It is called as (*event_callback)(event_stream, "tag", arg).
+
+   Events:
+     <insn pc='%p'>             begin an instruction, at a given location
+     </insn pc='%d'>            end an instruction, at a given location
+     <addr value='%p'/>         emit the symbolic value of an address
+
+   A tag format is one of three basic forms: "tag", "/tag", "tag/",
+   where tag is a simple identifier, signifying (as in XML) a element start,
+   element end, and standalone element.  (To render as XML, add angle brackets.)
+*/
+extern
+#ifdef DLL_EXPORT
+  DLL_EXPORT
+#endif
+void* decode_instructions(void* start, void* end,
+                          void* (*event_callback)(void*, const char*, void*),
+                          void* event_stream,
+                          int (*printf_callback)(void*, const char*, ...),
+                          void* printf_stream,
+                          const char* options);
+
+/* convenience typedefs */
+
+typedef void* (*decode_instructions_event_callback_ftype)  (void*, const char*, void*);
+typedef int   (*decode_instructions_printf_callback_ftype) (void*, const char*, ...);
+typedef void* (*decode_instructions_ftype) (void* start, void* end,
+                                            decode_instructions_event_callback_ftype event_callback,
+                                            void* event_stream,
+                                            decode_instructions_printf_callback_ftype printf_callback,
+                                            void* printf_stream,
+                                            const char* options);
--- a/hotspot/src/share/vm/asm/codeBuffer.cpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/asm/codeBuffer.cpp	Fri Apr 11 09:56:35 2008 -0400
@@ -947,6 +947,7 @@
   if (_comments != NULL) {
     CodeComment* c = _comments->find(offset);
     while (c && c->offset() == offset) {
+      stream->bol();
       stream->print("  ;; ");
       stream->print_cr(c->comment());
       c = c->next();
--- a/hotspot/src/share/vm/classfile/javaClasses.cpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/classfile/javaClasses.cpp	Fri Apr 11 09:56:35 2008 -0400
@@ -1015,7 +1015,6 @@
   typeArrayOop    _bcis;
   int             _index;
   bool            _dirty;
-  bool            _done;
   No_Safepoint_Verifier _nsv;
 
  public:
@@ -1029,12 +1028,10 @@
   };
 
   // constructor for new backtrace
-  BacktraceBuilder(TRAPS): _methods(NULL), _bcis(NULL), _head(NULL) {
+  BacktraceBuilder(TRAPS): _methods(NULL), _bcis(NULL), _head(NULL), _dirty(false) {
     expand(CHECK);
     _backtrace = _head;
     _index = 0;
-    _dirty = false;
-    _done = false;
   }
 
   void flush() {
--- a/hotspot/src/share/vm/code/codeCache.hpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/code/codeCache.hpp	Fri Apr 11 09:56:35 2008 -0400
@@ -71,7 +71,22 @@
   // what you are doing)
   static CodeBlob* find_blob_unsafe(void* start) {
     CodeBlob* result = (CodeBlob*)_heap->find_start(start);
-    assert(result == NULL || result->blob_contains((address)start), "found wrong CodeBlob");
+    // this assert is too strong because the heap code will return the
+    // heapblock containing start. That block can often be larger than
+    // the codeBlob itself. If you look up an address that is within
+    // the heapblock but not in the codeBlob you will assert.
+    //
+    // Most things will not lookup such bad addresses. However
+    // AsyncGetCallTrace can see intermediate frames and get that kind
+    // of invalid address and so can a developer using hsfind.
+    //
+    // The more correct answer is to return NULL if blob_contains() returns
+    // false.
+    // assert(result == NULL || result->blob_contains((address)start), "found wrong CodeBlob");
+
+    if (result != NULL && !result->blob_contains((address)start)) {
+      result = NULL;
+    }
     return result;
   }
 
--- a/hotspot/src/share/vm/code/nmethod.cpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/code/nmethod.cpp	Fri Apr 11 09:56:35 2008 -0400
@@ -707,7 +707,9 @@
            " entry points must be same for static methods and vice versa");
   }
 
-  bool printnmethods = PrintNMethods || CompilerOracle::has_option_string(_method, "PrintNMethods");
+  bool printnmethods = PrintNMethods
+    || CompilerOracle::should_print(_method)
+    || CompilerOracle::has_option_string(_method, "PrintNMethods");
   if (printnmethods || PrintDebugInfo || PrintRelocations || PrintDependencies || PrintExceptionHandlers) {
     print_nmethod(printnmethods);
   }
@@ -798,7 +800,6 @@
 }
 
 
-#ifndef PRODUCT
 void nmethod::print_nmethod(bool printmethod) {
   ttyLocker ttyl;  // keep the following output all in one block
   if (xtty != NULL) {
@@ -831,7 +832,6 @@
     xtty->tail("print_nmethod");
   }
 }
-#endif
 
 
 void nmethod::set_version(int v) {
@@ -1870,6 +1870,7 @@
   }
 }
 
+#endif // PRODUCT
 
 // Printing operations
 
@@ -1948,6 +1949,14 @@
                                               oops_size());
 }
 
+void nmethod::print_code() {
+  HandleMark hm;
+  ResourceMark m;
+  Disassembler::decode(this);
+}
+
+
+#ifndef PRODUCT
 
 void nmethod::print_scopes() {
   // Find the first pc desc for all scopes in the code and print it.
@@ -1979,13 +1988,6 @@
 }
 
 
-void nmethod::print_code() {
-  HandleMark hm;
-  ResourceMark m;
-  Disassembler().decode(this);
-}
-
-
 void nmethod::print_relocations() {
   ResourceMark m;       // in case methods get printed via the debugger
   tty->print_cr("relocations:");
@@ -2021,6 +2023,7 @@
   }
 }
 
+#endif // PRODUCT
 
 const char* nmethod::reloc_string_for(u_char* begin, u_char* end) {
   RelocIterator iter(this, begin, end);
@@ -2055,7 +2058,6 @@
   return have_one ? "other" : NULL;
 }
 
-
 // Return a the last scope in (begin..end]
 ScopeDesc* nmethod::scope_desc_in(address begin, address end) {
   PcDesc* p = pc_desc_near(begin+1);
@@ -2078,29 +2080,26 @@
       address pc = base + om->offset();
       if (pc > begin) {
         if (pc <= end) {
-          st->fill_to(column);
-          if (st == tty) {
-            st->print("; OopMap ");
-            om->print();
-            tty->cr();
-          } else {
-            st->print_cr("; OopMap #%d offset:%d", i, om->offset());
-          }
+          st->move_to(column);
+          st->print("; ");
+          om->print_on(st);
         }
         break;
       }
     }
   }
+
+  // Print any debug info present at this pc.
   ScopeDesc* sd  = scope_desc_in(begin, end);
   if (sd != NULL) {
-    st->fill_to(column);
+    st->move_to(column);
     if (sd->bci() == SynchronizationEntryBCI) {
       st->print(";*synchronization entry");
     } else {
       if (sd->method().is_null()) {
-        tty->print("method is NULL");
+        st->print("method is NULL");
       } else if (sd->method()->is_native()) {
-        tty->print("method is native");
+        st->print("method is native");
       } else {
         address bcp  = sd->method()->bcp_from(sd->bci());
         Bytecodes::Code bc = Bytecodes::java_code_at(bcp);
@@ -2137,13 +2136,13 @@
         }
       }
     }
-    st->cr();
+
     // Print all scopes
     for (;sd != NULL; sd = sd->sender()) {
-      st->fill_to(column);
+      st->move_to(column);
       st->print("; -");
       if (sd->method().is_null()) {
-        tty->print("method is NULL");
+        st->print("method is NULL");
       } else {
         sd->method()->print_short_name(st);
       }
@@ -2161,17 +2160,19 @@
   const char* str = reloc_string_for(begin, end);
   if (str != NULL) {
     if (sd != NULL) st->cr();
-    st->fill_to(column);
+    st->move_to(column);
     st->print(";   {%s}", str);
   }
   int cont_offset = ImplicitExceptionTable(this).at(begin - instructions_begin());
   if (cont_offset != 0) {
-    st->fill_to(column);
+    st->move_to(column);
     st->print("; implicit exception: dispatches to " INTPTR_FORMAT, instructions_begin() + cont_offset);
   }
 
 }
 
+#ifndef PRODUCT
+
 void nmethod::print_value_on(outputStream* st) const {
   print_on(st, "nmethod");
 }
--- a/hotspot/src/share/vm/code/nmethod.hpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/code/nmethod.hpp	Fri Apr 11 09:56:35 2008 -0400
@@ -485,8 +485,8 @@
   void verify_interrupt_point(address interrupt_point);
 
   // printing support
-  void print()                          const     PRODUCT_RETURN;
-  void print_code()                               PRODUCT_RETURN;
+  void print()                          const;
+  void print_code();
   void print_relocations()                        PRODUCT_RETURN;
   void print_pcs()                                PRODUCT_RETURN;
   void print_scopes()                             PRODUCT_RETURN;
@@ -495,7 +495,7 @@
   void print_calls(outputStream* st)              PRODUCT_RETURN;
   void print_handler_table()                      PRODUCT_RETURN;
   void print_nul_chk_table()                      PRODUCT_RETURN;
-  void print_nmethod(bool print_code)             PRODUCT_RETURN;
+  void print_nmethod(bool print_code);
 
   void print_on(outputStream* st, const char* title) const;
 
@@ -505,7 +505,7 @@
   void log_state_change(int state) const;
 
   // Prints a comment for one native instruction (reloc info, pc desc)
-  void print_code_comment_on(outputStream* st, int column, address begin, address end) PRODUCT_RETURN;
+  void print_code_comment_on(outputStream* st, int column, address begin, address end);
   static void print_statistics()                  PRODUCT_RETURN;
 
   // Compiler task identification.  Note that all OSR methods
--- a/hotspot/src/share/vm/code/vmreg.cpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/code/vmreg.cpp	Fri Apr 11 09:56:35 2008 -0400
@@ -36,7 +36,6 @@
 // Register names
 const char *VMRegImpl::regName[ConcreteRegisterImpl::number_of_registers];
 
-#ifndef PRODUCT
 void VMRegImpl::print_on(outputStream* st) const {
   if( is_reg() ) {
     assert( VMRegImpl::regName[value()], "" );
@@ -48,4 +47,3 @@
     st->print("BAD!");
   }
 }
-#endif // PRODUCT
--- a/hotspot/src/share/vm/code/vmreg.hpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/code/vmreg.hpp	Fri Apr 11 09:56:35 2008 -0400
@@ -96,7 +96,7 @@
 
   intptr_t value() const         {return (intptr_t) this; }
 
-  void print_on(outputStream* st) const PRODUCT_RETURN;
+  void print_on(outputStream* st) const;
   void print() const { print_on(tty); }
 
   // bias a stack slot.
@@ -156,22 +156,22 @@
     _first = ptr;
   }
   // Return true if single register, even if the pair is really just adjacent stack slots
-  bool is_single_reg() {
+  bool is_single_reg() const {
     return (_first->is_valid()) && (_first->value() + 1 == _second->value());
   }
 
   // Return true if single stack based "register" where the slot alignment matches input alignment
-  bool is_adjacent_on_stack(int alignment) {
+  bool is_adjacent_on_stack(int alignment) const {
     return (_first->is_stack() && (_first->value() + 1 == _second->value()) && ((_first->value() & (alignment-1)) == 0));
   }
 
   // Return true if single stack based "register" where the slot alignment matches input alignment
-  bool is_adjacent_aligned_on_stack(int alignment) {
+  bool is_adjacent_aligned_on_stack(int alignment) const {
     return (_first->is_stack() && (_first->value() + 1 == _second->value()) && ((_first->value() & (alignment-1)) == 0));
   }
 
   // Return true if single register but adjacent stack slots do not count
-  bool is_single_phys_reg() {
+  bool is_single_phys_reg() const {
     return (_first->is_reg() && (_first->value() + 1 == _second->value()));
   }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/compiler/disassembler.cpp	Fri Apr 11 09:56:35 2008 -0400
@@ -0,0 +1,443 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+# include "incls/_precompiled.incl"
+# include "incls/_disassembler.cpp.incl"
+
+void*       Disassembler::_library               = NULL;
+bool        Disassembler::_tried_to_load_library = false;
+
+// This routine is in the shared library:
+Disassembler::decode_func Disassembler::_decode_instructions = NULL;
+
+static const char hsdis_library_name[] = "hsdis-"HOTSPOT_LIB_ARCH;
+static const char decode_instructions_name[] = "decode_instructions";
+
+#define COMMENT_COLUMN  40 LP64_ONLY(+8) /*could be an option*/
+#define BYTES_COMMENT   ";..."  /* funky byte display comment */
+
+bool Disassembler::load_library() {
+  if (_decode_instructions != NULL) {
+    // Already succeeded.
+    return true;
+  }
+  if (_tried_to_load_library) {
+    // Do not try twice.
+    // To force retry in debugger: assign _tried_to_load_library=0
+    return false;
+  }
+  // Try to load it.
+  char ebuf[1024];
+  char buf[JVM_MAXPATHLEN];
+  os::jvm_path(buf, sizeof(buf));
+  int jvm_offset = -1;
+  {
+    // Match "jvm[^/]*" in jvm_path.
+    const char* base = buf;
+    const char* p = strrchr(buf, '/');
+    p = strstr(p ? p : base, "jvm");
+    if (p != NULL)  jvm_offset = p - base;
+  }
+  if (jvm_offset >= 0) {
+    // Find the disassembler next to libjvm.so.
+    strcpy(&buf[jvm_offset], hsdis_library_name);
+    strcat(&buf[jvm_offset], os::dll_file_extension());
+    _library = hpi::dll_load(buf, ebuf, sizeof ebuf);
+  }
+  if (_library == NULL) {
+    // Try a free-floating lookup.
+    strcpy(&buf[0], hsdis_library_name);
+    strcat(&buf[0], os::dll_file_extension());
+    _library = hpi::dll_load(buf, ebuf, sizeof ebuf);
+  }
+  if (_library != NULL) {
+    _decode_instructions = CAST_TO_FN_PTR(Disassembler::decode_func,
+                                          hpi::dll_lookup(_library, decode_instructions_name));
+  }
+  _tried_to_load_library = true;
+  if (_decode_instructions == NULL) {
+    tty->print_cr("Could not load %s; %s; %s", buf,
+                  ((_library != NULL)
+                   ? "entry point is missing"
+                   : (WizardMode || PrintMiscellaneous)
+                   ? (const char*)ebuf
+                   : "library not loadable"),
+                  "PrintAssembly is disabled");
+    return false;
+  }
+
+  // Success.
+  tty->print_cr("Loaded disassembler from %s", buf);
+  return true;
+}
+
+
+class decode_env {
+ private:
+  nmethod*      _nm;
+  CodeBlob*     _code;
+  outputStream* _output;
+  address       _start, _end;
+
+  char          _option_buf[512];
+  char          _print_raw;
+  bool          _print_pc;
+  bool          _print_bytes;
+  address       _cur_insn;
+  int           _total_ticks;
+  int           _bytes_per_line; // arch-specific formatting option
+
+  static bool match(const char* event, const char* tag) {
+    size_t taglen = strlen(tag);
+    if (strncmp(event, tag, taglen) != 0)
+      return false;
+    char delim = event[taglen];
+    return delim == '\0' || delim == ' ' || delim == '/' || delim == '=';
+  }
+
+  void collect_options(const char* p) {
+    if (p == NULL || p[0] == '\0')  return;
+    size_t opt_so_far = strlen(_option_buf);
+    if (opt_so_far + 1 + strlen(p) + 1 > sizeof(_option_buf))  return;
+    char* fillp = &_option_buf[opt_so_far];
+    if (opt_so_far > 0) *fillp++ = ',';
+    strcat(fillp, p);
+    // replace white space by commas:
+    char* q = fillp;
+    while ((q = strpbrk(q, " \t\n")) != NULL)
+      *q++ = ',';
+    // Note that multiple PrintAssemblyOptions flags accumulate with \n,
+    // which we want to be changed to a comma...
+  }
+
+  void print_insn_labels();
+  void print_insn_bytes(address pc0, address pc);
+  void print_address(address value);
+
+ public:
+  decode_env(CodeBlob* code, outputStream* output);
+
+  address decode_instructions(address start, address end);
+
+  void start_insn(address pc) {
+    _cur_insn = pc;
+    output()->bol();
+    print_insn_labels();
+  }
+
+  void end_insn(address pc) {
+    address pc0 = cur_insn();
+    outputStream* st = output();
+    if (_print_bytes && pc > pc0)
+      print_insn_bytes(pc0, pc);
+    if (_nm != NULL)
+      _nm->print_code_comment_on(st, COMMENT_COLUMN, pc0, pc);
+
+    // Output pc bucket ticks if we have any
+    if (total_ticks() != 0) {
+      address bucket_pc = FlatProfiler::bucket_start_for(pc);
+      if (bucket_pc != NULL && bucket_pc > pc0 && bucket_pc <= pc) {
+        int bucket_count = FlatProfiler::bucket_count_for(pc0);
+        if (bucket_count != 0) {
+          st->bol();
+          st->print_cr("%3.1f%% [%d]", bucket_count*100.0/total_ticks(), bucket_count);
+        }
+      }
+    }
+  }
+
+  address handle_event(const char* event, address arg);
+
+  outputStream* output() { return _output; }
+  address cur_insn() { return _cur_insn; }
+  int total_ticks() { return _total_ticks; }
+  void set_total_ticks(int n) { _total_ticks = n; }
+  const char* options() { return _option_buf; }
+};
+
+decode_env::decode_env(CodeBlob* code, outputStream* output) {
+  memset(this, 0, sizeof(*this));
+  _output = output ? output : tty;
+  _code = code;
+  if (code != NULL && code->is_nmethod())
+    _nm = (nmethod*) code;
+
+  // by default, output pc but not bytes:
+  _print_pc       = true;
+  _print_bytes    = false;
+  _bytes_per_line = Disassembler::pd_instruction_alignment();
+
+  // parse the global option string:
+  collect_options(Disassembler::pd_cpu_opts());
+  collect_options(PrintAssemblyOptions);
+
+  if (strstr(options(), "hsdis-")) {
+    if (strstr(options(), "hsdis-print-raw"))
+      _print_raw = (strstr(options(), "xml") ? 2 : 1);
+    if (strstr(options(), "hsdis-print-pc"))
+      _print_pc = !_print_pc;
+    if (strstr(options(), "hsdis-print-bytes"))
+      _print_bytes = !_print_bytes;
+  }
+  if (strstr(options(), "help")) {
+    tty->print_cr("PrintAssemblyOptions help:");
+    tty->print_cr("  hsdis-print-raw       test plugin by requesting raw output");
+    tty->print_cr("  hsdis-print-raw-xml   test plugin by requesting raw xml");
+    tty->print_cr("  hsdis-print-pc        turn off PC printing (on by default)");
+    tty->print_cr("  hsdis-print-bytes     turn on instruction byte output");
+    tty->print_cr("combined options: %s", options());
+  }
+}
+
+address decode_env::handle_event(const char* event, address arg) {
+  if (match(event, "insn")) {
+    start_insn(arg);
+  } else if (match(event, "/insn")) {
+    end_insn(arg);
+  } else if (match(event, "addr")) {
+    if (arg != NULL) {
+      print_address(arg);
+      return arg;
+    }
+  } else if (match(event, "mach")) {
+   output()->print_cr("[Disassembling for mach='%s']", arg);
+  } else if (match(event, "format bytes-per-line")) {
+    _bytes_per_line = (int) (intptr_t) arg;
+  } else {
+    // ignore unrecognized markup
+  }
+  return NULL;
+}
+
+// called by the disassembler to print out jump targets and data addresses
+void decode_env::print_address(address adr) {
+  outputStream* st = _output;
+
+  if (adr == NULL) {
+    st->print("NULL");
+    return;
+  }
+
+  int small_num = (int)(intptr_t)adr;
+  if ((intptr_t)adr == (intptr_t)small_num
+      && -1 <= small_num && small_num <= 9) {
+    st->print("%d", small_num);
+    return;
+  }
+
+  if (Universe::is_fully_initialized()) {
+    if (StubRoutines::contains(adr)) {
+      StubCodeDesc* desc = StubCodeDesc::desc_for(adr);
+      if (desc == NULL)
+        desc = StubCodeDesc::desc_for(adr + frame::pc_return_offset);
+      if (desc != NULL) {
+        st->print("Stub::%s", desc->name());
+        if (desc->begin() != adr)
+          st->print("%+d 0x%p",adr - desc->begin(), adr);
+        else if (WizardMode) st->print(" " INTPTR_FORMAT, adr);
+        return;
+      }
+      st->print("Stub::<unknown> " INTPTR_FORMAT, adr);
+      return;
+    }
+
+    BarrierSet* bs = Universe::heap()->barrier_set();
+    if (bs->kind() == BarrierSet::CardTableModRef &&
+        adr == (address)((CardTableModRefBS*)(bs))->byte_map_base) {
+      st->print("word_map_base");
+      if (WizardMode) st->print(" " INTPTR_FORMAT, (intptr_t)adr);
+      return;
+    }
+
+    oop obj;
+    if (_nm != NULL
+        && (obj = _nm->embeddedOop_at(cur_insn())) != NULL
+        && (address) obj == adr) {
+      obj->print_value_on(st);
+      return;
+    }
+  }
+
+  // Fall through to a simple numeral.
+  st->print(INTPTR_FORMAT, (intptr_t)adr);
+}
+
+void decode_env::print_insn_labels() {
+  address p = cur_insn();
+  outputStream* st = output();
+  nmethod* nm = _nm;
+  if (nm != NULL) {
+    if (p == nm->entry_point())             st->print_cr("[Entry Point]");
+    if (p == nm->verified_entry_point())    st->print_cr("[Verified Entry Point]");
+    if (p == nm->exception_begin())         st->print_cr("[Exception Handler]");
+    if (p == nm->stub_begin())              st->print_cr("[Stub Code]");
+    if (p == nm->consts_begin())            st->print_cr("[Constants]");
+  }
+  CodeBlob* cb = _code;
+  if (cb != NULL) {
+    cb->print_block_comment(st, (intptr_t)(p - cb->instructions_begin()));
+  }
+  if (_print_pc) {
+    st->print("  " INTPTR_FORMAT ": ", (intptr_t) p);
+  }
+}
+
+void decode_env::print_insn_bytes(address pc, address pc_limit) {
+  outputStream* st = output();
+  size_t incr = 1;
+  size_t perline = _bytes_per_line;
+  if ((size_t) Disassembler::pd_instruction_alignment() >= sizeof(int)
+      && !((uintptr_t)pc % sizeof(int))
+      && !((uintptr_t)pc_limit % sizeof(int))) {
+    incr = sizeof(int);
+    if (perline % incr)  perline += incr - (perline % incr);
+  }
+  while (pc < pc_limit) {
+    // tab to the desired column:
+    st->move_to(COMMENT_COLUMN);
+    address pc0 = pc;
+    address pc1 = pc + perline;
+    if (pc1 > pc_limit)  pc1 = pc_limit;
+    for (; pc < pc1; pc += incr) {
+      if (pc == pc0)
+        st->print(BYTES_COMMENT);
+      else if ((uint)(pc - pc0) % sizeof(int) == 0)
+        st->print(" ");         // put out a space on word boundaries
+      if (incr == sizeof(int))
+            st->print("%08lx", *(int*)pc);
+      else  st->print("%02x",   (*pc)&0xFF);
+    }
+    st->cr();
+  }
+}
+
+
+static void* event_to_env(void* env_pv, const char* event, void* arg) {
+  decode_env* env = (decode_env*) env_pv;
+  return env->handle_event(event, (address) arg);
+}
+
+static int printf_to_env(void* env_pv, const char* format, ...) {
+  decode_env* env = (decode_env*) env_pv;
+  outputStream* st = env->output();
+  size_t flen = strlen(format);
+  const char* raw = NULL;
+  if (flen == 0)  return 0;
+  if (flen == 1 && format[0] == '\n') { st->bol(); return 1; }
+  if (flen < 2 ||
+      strchr(format, '%') == NULL) {
+    raw = format;
+  } else if (format[0] == '%' && format[1] == '%' &&
+             strchr(format+2, '%') == NULL) {
+    // happens a lot on machines with names like %foo
+    flen--;
+    raw = format+1;
+  }
+  if (raw != NULL) {
+    st->print_raw(raw, (int) flen);
+    return (int) flen;
+  }
+  va_list ap;
+  va_start(ap, format);
+  julong cnt0 = st->count();
+  st->vprint(format, ap);
+  julong cnt1 = st->count();
+  va_end(ap);
+  return (int)(cnt1 - cnt0);
+}
+
+address decode_env::decode_instructions(address start, address end) {
+  _start = start; _end = end;
+
+  assert((((intptr_t)start | (intptr_t)end) % Disassembler::pd_instruction_alignment() == 0), "misaligned insn addr");
+
+  const int show_bytes = false; // for disassembler debugging
+
+  //_version = Disassembler::pd_cpu_version();
+
+  if (!Disassembler::can_decode()) {
+    return NULL;
+  }
+
+  // decode a series of instructions and return the end of the last instruction
+
+  if (_print_raw) {
+    // Print whatever the library wants to print, w/o fancy callbacks.
+    // This is mainly for debugging the library itself.
+    FILE* out = stdout;
+    FILE* xmlout = (_print_raw > 1 ? out : NULL);
+    return (address)
+      (*Disassembler::_decode_instructions)(start, end,
+                                            NULL, (void*) xmlout,
+                                            NULL, (void*) out,
+                                            options());
+  }
+
+  return (address)
+    (*Disassembler::_decode_instructions)(start, end,
+                                          &event_to_env,  (void*) this,
+                                          &printf_to_env, (void*) this,
+                                          options());
+}
+
+
+void Disassembler::decode(CodeBlob* cb, outputStream* st) {
+  if (!load_library())  return;
+  decode_env env(cb, st);
+  env.output()->print_cr("Decoding CodeBlob " INTPTR_FORMAT, cb);
+  env.decode_instructions(cb->instructions_begin(), cb->instructions_end());
+}
+
+
+void Disassembler::decode(address start, address end, outputStream* st) {
+  if (!load_library())  return;
+  decode_env env(CodeCache::find_blob_unsafe(start), st);
+  env.decode_instructions(start, end);
+}
+
+void Disassembler::decode(nmethod* nm, outputStream* st) {
+  if (!load_library())  return;
+  decode_env env(nm, st);
+  env.output()->print_cr("Decoding compiled method " INTPTR_FORMAT ":", nm);
+  env.output()->print_cr("Code:");
+
+  unsigned char* p = nm->instructions_begin();
+  unsigned char* end = nm->instructions_end();
+
+  // If there has been profiling, print the buckets.
+  if (FlatProfiler::bucket_start_for(p) != NULL) {
+    unsigned char* p1 = p;
+    int total_bucket_count = 0;
+    while (p1 < end) {
+      unsigned char* p0 = p1;
+      p1 += pd_instruction_alignment();
+      address bucket_pc = FlatProfiler::bucket_start_for(p1);
+      if (bucket_pc != NULL && bucket_pc > p0 && bucket_pc <= p1)
+        total_bucket_count += FlatProfiler::bucket_count_for(p0);
+    }
+    env.set_total_ticks(total_bucket_count);
+  }
+
+  env.decode_instructions(p, end);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/compiler/disassembler.hpp	Fri Apr 11 09:56:35 2008 -0400
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+class decode_env;
+
+// The disassembler prints out assembly code annotated
+// with Java specific information.
+
+class Disassembler {
+  friend class decode_env;
+ private:
+  // this is the type of the dll entry point:
+  typedef void* (*decode_func)(void* start, void* end,
+                               void* (*event_callback)(void*, const char*, void*),
+                               void* event_stream,
+                               int (*printf_callback)(void*, const char*, ...),
+                               void* printf_stream,
+                               const char* options);
+  // points to the library.
+  static void*    _library;
+  // bailout
+  static bool     _tried_to_load_library;
+  // points to the decode function.
+  static decode_func _decode_instructions;
+  // tries to load library and return whether it succedded.
+  static bool load_library();
+
+  // Machine dependent stuff
+  #include "incls/_disassembler_pd.hpp.incl"
+
+ public:
+  static bool can_decode() {
+    return (_decode_instructions != NULL) || load_library();
+  }
+  static void decode(CodeBlob *cb,               outputStream* st = NULL);
+  static void decode(nmethod* nm,                outputStream* st = NULL);
+  static void decode(address begin, address end, outputStream* st = NULL);
+};
--- a/hotspot/src/share/vm/compiler/disassemblerEnv.hpp	Thu Apr 10 15:49:16 2008 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Copyright 1997-2002 Sun Microsystems, Inc.  All Rights Reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- *
- */
-
-// Call-back interface for external disassembler
-class DisassemblerEnv {
- public:
-  // printing
-  virtual void print_label(intptr_t value)   = 0;
-  virtual void print_raw(char* str)     = 0;
-  virtual void print(char* format, ...) = 0;
-  // helpers
-  virtual char* string_for_offset(intptr_t value) = 0;
-  virtual char* string_for_constant(unsigned char* pc, intptr_t value, int is_decimal) = 0;
-};
--- a/hotspot/src/share/vm/compiler/oopMap.cpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/compiler/oopMap.cpp	Fri Apr 11 09:56:35 2008 -0400
@@ -505,8 +505,13 @@
 #endif // COMPILER2
 }
 
+#endif //PRODUCT
 
-static void print_register_type(OopMapValue::oop_types x, VMReg optional, outputStream* st) {
+// Printing code is present in product build for -XX:+PrintAssembly.
+
+static
+void print_register_type(OopMapValue::oop_types x, VMReg optional,
+                         outputStream* st) {
   switch( x ) {
   case OopMapValue::oop_value:
     st->print("Oop");
@@ -544,10 +549,12 @@
 
 void OopMap::print_on(outputStream* st) const {
   OopMapValue omv;
+  st->print("OopMap{");
   for(OopMapStream oms((OopMap*)this); !oms.is_done(); oms.next()) {
     omv = oms.current();
     omv.print_on(st);
   }
+  st->print("off=%d}", (int) offset());
 }
 
 
@@ -558,12 +565,12 @@
 
   for( i = 0; i < len; i++) {
     OopMap* m = at(i);
-    st->print_cr("OopMap #%d offset:%p",i,m->offset());
+    st->print_cr("#%d ",i);
     m->print_on(st);
-    st->print_cr("\n");
+    st->cr();
   }
 }
-#endif // !PRODUCT
+
 
 
 //------------------------------DerivedPointerTable---------------------------
--- a/hotspot/src/share/vm/compiler/oopMap.hpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/compiler/oopMap.hpp	Fri Apr 11 09:56:35 2008 -0400
@@ -129,7 +129,7 @@
     return reg()->reg2stack();
   }
 
-  void print_on(outputStream* st) const PRODUCT_RETURN;
+  void print_on(outputStream* st) const;
   void print() const { print_on(tty); }
 };
 
@@ -193,7 +193,7 @@
   }
 
   // Printing
-  void print_on(outputStream* st) const PRODUCT_RETURN;
+  void print_on(outputStream* st) const;
   void print() const { print_on(tty); }
 };
 
@@ -248,7 +248,7 @@
                      OopClosure* value_fn, OopClosure* dead_fn);
 
   // Printing
-  void print_on(outputStream* st) const PRODUCT_RETURN;
+  void print_on(outputStream* st) const;
   void print() const { print_on(tty); }
 };
 
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp	Fri Apr 11 09:56:35 2008 -0400
@@ -225,6 +225,34 @@
   assert(_dilatation_factor >= 1.0, "from previous assert");
 }
 
+
+// The field "_initiating_occupancy" represents the occupancy percentage
+// at which we trigger a new collection cycle.  Unless explicitly specified
+// via CMSInitiating[Perm]OccupancyFraction (argument "io" below), it
+// is calculated by:
+//
+//   Let "f" be MinHeapFreeRatio in
+//
+//    _intiating_occupancy = 100-f +
+//                           f * (CMSTrigger[Perm]Ratio/100)
+//   where CMSTrigger[Perm]Ratio is the argument "tr" below.
+//
+// That is, if we assume the heap is at its desired maximum occupancy at the
+// end of a collection, we let CMSTrigger[Perm]Ratio of the (purported) free
+// space be allocated before initiating a new collection cycle.
+//
+void ConcurrentMarkSweepGeneration::init_initiating_occupancy(intx io, intx tr) {
+  assert(io <= 100 && tr >= 0 && tr <= 100, "Check the arguments");
+  if (io >= 0) {
+    _initiating_occupancy = (double)io / 100.0;
+  } else {
+    _initiating_occupancy = ((100 - MinHeapFreeRatio) +
+                             (double)(tr * MinHeapFreeRatio) / 100.0)
+                            / 100.0;
+  }
+}
+
+
 void ConcurrentMarkSweepGeneration::ref_processor_init() {
   assert(collector() != NULL, "no collector");
   collector()->ref_processor_init();
@@ -520,8 +548,8 @@
   _verification_mark_bm(0, Mutex::leaf + 1, "CMS_verification_mark_bm_lock"),
   _completed_initialization(false),
   _collector_policy(cp),
-  _unload_classes(false),
-  _unloaded_classes_last_cycle(false),
+  _should_unload_classes(false),
+  _concurrent_cycles_since_last_unload(0),
   _sweep_estimate(CMS_SweepWeight, CMS_SweepPadding)
 {
   if (ExplicitGCInvokesConcurrentAndUnloadsClasses) {
@@ -642,26 +670,11 @@
     }
   }
 
-  // "initiatingOccupancy" is the occupancy ratio at which we trigger
-  // a new collection cycle.  Unless explicitly specified via
-  // CMSTriggerRatio, it is calculated by:
-  //   Let "f" be MinHeapFreeRatio in
-  //
-  //    intiatingOccupancy = 100-f +
-  //                         f * (CMSTriggerRatio/100)
-  // That is, if we assume the heap is at its desired maximum occupancy at the
-  // end of a collection, we let CMSTriggerRatio of the (purported) free
-  // space be allocated before initiating a new collection cycle.
-  if (CMSInitiatingOccupancyFraction > 0) {
-    _initiatingOccupancy = (double)CMSInitiatingOccupancyFraction / 100.0;
-  } else {
-    _initiatingOccupancy = ((100 - MinHeapFreeRatio) +
-                           (double)(CMSTriggerRatio *
-                                    MinHeapFreeRatio) / 100.0)
-                           / 100.0;
-  }
+  _cmsGen ->init_initiating_occupancy(CMSInitiatingOccupancyFraction, CMSTriggerRatio);
+  _permGen->init_initiating_occupancy(CMSInitiatingPermOccupancyFraction, CMSTriggerPermRatio);
+
   // Clip CMSBootstrapOccupancy between 0 and 100.
-  _bootstrap_occupancy = ((double)MIN2((intx)100, MAX2((intx)0, CMSBootstrapOccupancy)))
+  _bootstrap_occupancy = ((double)MIN2((uintx)100, MAX2((uintx)0, CMSBootstrapOccupancy)))
                          /(double)100;
 
   _full_gcs_since_conc_gc = 0;
@@ -1413,7 +1426,8 @@
     gclog_or_tty->print_cr("promotion_rate=%g", stats().promotion_rate());
     gclog_or_tty->print_cr("cms_allocation_rate=%g", stats().cms_allocation_rate());
     gclog_or_tty->print_cr("occupancy=%3.7f", _cmsGen->occupancy());
-    gclog_or_tty->print_cr("initiatingOccupancy=%3.7f", initiatingOccupancy());
+    gclog_or_tty->print_cr("initiatingOccupancy=%3.7f", _cmsGen->initiating_occupancy());
+    gclog_or_tty->print_cr("initiatingPermOccupancy=%3.7f", _permGen->initiating_occupancy());
   }
   // ------------------------------------------------------------------
 
@@ -1446,22 +1460,36 @@
   // old gen want a collection cycle started. Each may use
   // an appropriate criterion for making this decision.
   // XXX We need to make sure that the gen expansion
-  // criterion dovetails well with this.
-  if (_cmsGen->shouldConcurrentCollect(initiatingOccupancy())) {
+  // criterion dovetails well with this. XXX NEED TO FIX THIS
+  if (_cmsGen->should_concurrent_collect()) {
     if (Verbose && PrintGCDetails) {
       gclog_or_tty->print_cr("CMS old gen initiated");
     }
     return true;
   }
 
-  if (cms_should_unload_classes() &&
-      _permGen->shouldConcurrentCollect(initiatingOccupancy())) {
-    if (Verbose && PrintGCDetails) {
-     gclog_or_tty->print_cr("CMS perm gen initiated");
+  // We start a collection if we believe an incremental collection may fail;
+  // this is not likely to be productive in practice because it's probably too
+  // late anyway.
+  GenCollectedHeap* gch = GenCollectedHeap::heap();
+  assert(gch->collector_policy()->is_two_generation_policy(),
+         "You may want to check the correctness of the following");
+  if (gch->incremental_collection_will_fail()) {
+    if (PrintGCDetails && Verbose) {
+      gclog_or_tty->print("CMSCollector: collect because incremental collection will fail ");
     }
     return true;
   }
 
+  if (CMSClassUnloadingEnabled && _permGen->should_concurrent_collect()) {
+    bool res = update_should_unload_classes();
+    if (res) {
+      if (Verbose && PrintGCDetails) {
+        gclog_or_tty->print_cr("CMS perm gen initiated");
+      }
+      return true;
+    }
+  }
   return false;
 }
 
@@ -1471,32 +1499,36 @@
   _permGen->clear_expansion_cause();
 }
 
-bool ConcurrentMarkSweepGeneration::shouldConcurrentCollect(
-  double initiatingOccupancy) {
-  // We should be conservative in starting a collection cycle.  To
-  // start too eagerly runs the risk of collecting too often in the
-  // extreme.  To collect too rarely falls back on full collections,
-  // which works, even if not optimum in terms of concurrent work.
-  // As a work around for too eagerly collecting, use the flag
-  // UseCMSInitiatingOccupancyOnly.  This also has the advantage of
-  // giving the user an easily understandable way of controlling the
-  // collections.
-  // We want to start a new collection cycle if any of the following
-  // conditions hold:
-  // . our current occupancy exceeds the initiating occupancy, or
-  // . we recently needed to expand and have not since that expansion,
-  //   collected, or
-  // . we are not using adaptive free lists and linear allocation is
-  //   going to fail, or
-  // . (for old gen) incremental collection has already failed or
-  //   may soon fail in the near future as we may not be able to absorb
-  //   promotions.
+// We should be conservative in starting a collection cycle.  To
+// start too eagerly runs the risk of collecting too often in the
+// extreme.  To collect too rarely falls back on full collections,
+// which works, even if not optimum in terms of concurrent work.
+// As a work around for too eagerly collecting, use the flag
+// UseCMSInitiatingOccupancyOnly.  This also has the advantage of
+// giving the user an easily understandable way of controlling the
+// collections.
+// We want to start a new collection cycle if any of the following
+// conditions hold:
+// . our current occupancy exceeds the configured initiating occupancy
+//   for this generation, or
+// . we recently needed to expand this space and have not, since that
+//   expansion, done a collection of this generation, or
+// . the underlying space believes that it may be a good idea to initiate
+//   a concurrent collection (this may be based on criteria such as the
+//   following: the space uses linear allocation and linear allocation is
+//   going to fail, or there is believed to be excessive fragmentation in
+//   the generation, etc... or ...
+// [.(currently done by CMSCollector::shouldConcurrentCollect() only for
+//   the case of the old generation, not the perm generation; see CR 6543076):
+//   we may be approaching a point at which allocation requests may fail because
+//   we will be out of sufficient free space given allocation rate estimates.]
+bool ConcurrentMarkSweepGeneration::should_concurrent_collect() const {
+
   assert_lock_strong(freelistLock());
-
-  if (occupancy() > initiatingOccupancy) {
+  if (occupancy() > initiating_occupancy()) {
     if (PrintGCDetails && Verbose) {
       gclog_or_tty->print(" %s: collect because of occupancy %f / %f  ",
-        short_name(), occupancy(), initiatingOccupancy);
+        short_name(), occupancy(), initiating_occupancy());
     }
     return true;
   }
@@ -1510,20 +1542,9 @@
     }
     return true;
   }
-  GenCollectedHeap* gch = GenCollectedHeap::heap();
-  assert(gch->collector_policy()->is_two_generation_policy(),
-         "You may want to check the correctness of the following");
-  if (gch->incremental_collection_will_fail()) {
+  if (_cmsSpace->should_concurrent_collect()) {
     if (PrintGCDetails && Verbose) {
-      gclog_or_tty->print(" %s: collect because incremental collection will fail ",
-        short_name());
-    }
-    return true;
-  }
-  if (!_cmsSpace->adaptive_freelists() &&
-      _cmsSpace->linearAllocationWouldFail()) {
-    if (PrintGCDetails && Verbose) {
-      gclog_or_tty->print(" %s: collect because of linAB ",
+      gclog_or_tty->print(" %s: collect because cmsSpace says so ",
         short_name());
     }
     return true;
@@ -1970,8 +1991,9 @@
          "Should have been NULL'd before baton was passed");
   reset(false /* == !asynch */);
   _cmsGen->reset_after_compaction();
-
-  if (verifying() && !cms_should_unload_classes()) {
+  _concurrent_cycles_since_last_unload = 0;
+
+  if (verifying() && !should_unload_classes()) {
     perm_gen_verify_bit_map()->clear_all();
   }
 
@@ -2098,6 +2120,7 @@
   {
     bool safepoint_check = Mutex::_no_safepoint_check_flag;
     MutexLockerEx hl(Heap_lock, safepoint_check);
+    FreelistLocker fll(this);
     MutexLockerEx x(CGC_lock, safepoint_check);
     if (_foregroundGCIsActive || !UseAsyncConcMarkSweepGC) {
       // The foreground collector is active or we're
@@ -2112,13 +2135,9 @@
       // a new cycle.
       clear_expansion_cause();
     }
-    _unloaded_classes_last_cycle = cms_should_unload_classes(); // ... from last cycle
-    // This controls class unloading in response to an explicit gc request.
-    // If ExplicitGCInvokesConcurrentAndUnloadsClasses is set, then
-    // we will unload classes even if CMSClassUnloadingEnabled is not set.
-    // See CR 6541037 and related CRs.
-    _unload_classes = _full_gc_requested                      // ... for this cycle
-                      && ExplicitGCInvokesConcurrentAndUnloadsClasses;
+    // Decide if we want to enable class unloading as part of the
+    // ensuing concurrent GC cycle.
+    update_should_unload_classes();
     _full_gc_requested = false;           // acks all outstanding full gc requests
     // Signal that we are about to start a collection
     gch->increment_total_full_collections();  // ... starting a collection cycle
@@ -3047,21 +3066,62 @@
 }
 #endif // PRODUCT
 
+// Decide if we want to enable class unloading as part of the
+// ensuing concurrent GC cycle. We will collect the perm gen and
+// unload classes if it's the case that:
+// (1) an explicit gc request has been made and the flag
+//     ExplicitGCInvokesConcurrentAndUnloadsClasses is set, OR
+// (2) (a) class unloading is enabled at the command line, and
+//     (b) (i)   perm gen threshold has been crossed, or
+//         (ii)  old gen is getting really full, or
+//         (iii) the previous N CMS collections did not collect the
+//               perm gen
+// NOTE: Provided there is no change in the state of the heap between
+// calls to this method, it should have idempotent results. Moreover,
+// its results should be monotonically increasing (i.e. going from 0 to 1,
+// but not 1 to 0) between successive calls between which the heap was
+// not collected. For the implementation below, it must thus rely on
+// the property that concurrent_cycles_since_last_unload()
+// will not decrease unless a collection cycle happened and that
+// _permGen->should_concurrent_collect() and _cmsGen->is_too_full() are
+// themselves also monotonic in that sense. See check_monotonicity()
+// below.
+bool CMSCollector::update_should_unload_classes() {
+  _should_unload_classes = false;
+  // Condition 1 above
+  if (_full_gc_requested && ExplicitGCInvokesConcurrentAndUnloadsClasses) {
+    _should_unload_classes = true;
+  } else if (CMSClassUnloadingEnabled) { // Condition 2.a above
+    // Disjuncts 2.b.(i,ii,iii) above
+    _should_unload_classes = (concurrent_cycles_since_last_unload() >=
+                              CMSClassUnloadingMaxInterval)
+                           || _permGen->should_concurrent_collect()
+                           || _cmsGen->is_too_full();
+  }
+  return _should_unload_classes;
+}
+
+bool ConcurrentMarkSweepGeneration::is_too_full() const {
+  bool res = should_concurrent_collect();
+  res = res && (occupancy() > (double)CMSIsTooFullPercentage/100.0);
+  return res;
+}
+
 void CMSCollector::setup_cms_unloading_and_verification_state() {
   const  bool should_verify =    VerifyBeforeGC || VerifyAfterGC || VerifyDuringGC
                              || VerifyBeforeExit;
   const  int  rso           =    SharedHeap::SO_Symbols | SharedHeap::SO_Strings
                              |   SharedHeap::SO_CodeCache;
 
-  if (cms_should_unload_classes()) {   // Should unload classes this cycle
+  if (should_unload_classes()) {   // Should unload classes this cycle
     remove_root_scanning_option(rso);  // Shrink the root set appropriately
     set_verifying(should_verify);    // Set verification state for this cycle
     return;                            // Nothing else needs to be done at this time
   }
 
   // Not unloading classes this cycle
-  assert(!cms_should_unload_classes(), "Inconsitency!");
-  if ((!verifying() || cms_unloaded_classes_last_cycle()) && should_verify) {
+  assert(!should_unload_classes(), "Inconsitency!");
+  if ((!verifying() || unloaded_classes_last_cycle()) && should_verify) {
     // We were not verifying, or we _were_ unloading classes in the last cycle,
     // AND some verification options are enabled this cycle; in this case,
     // we must make sure that the deadness map is allocated if not already so,
@@ -4693,7 +4753,7 @@
 
   GenCollectedHeap* gch = GenCollectedHeap::heap();
 
-  if (cms_should_unload_classes()) {
+  if (should_unload_classes()) {
     CodeCache::gc_prologue();
   }
   assert(haveFreelistLocks(), "must have free list locks");
@@ -4753,7 +4813,7 @@
   verify_work_stacks_empty();
   verify_overflow_empty();
 
-  if (cms_should_unload_classes()) {
+  if (should_unload_classes()) {
     CodeCache::gc_epilogue();
   }
 
@@ -5623,7 +5683,7 @@
     verify_work_stacks_empty();
   }
 
-  if (cms_should_unload_classes()) {
+  if (should_unload_classes()) {
     {
       TraceTime t("class unloading", PrintGCDetails, false, gclog_or_tty);
 
@@ -5726,7 +5786,7 @@
   // this cycle, we preserve the perm gen object "deadness" information
   // in the perm_gen_verify_bit_map. In order to do that we traverse
   // all blocks in perm gen and mark all dead objects.
-  if (verifying() && !cms_should_unload_classes()) {
+  if (verifying() && !should_unload_classes()) {
     assert(perm_gen_verify_bit_map()->sizeInBits() != 0,
            "Should have already been allocated");
     MarkDeadObjectsClosure mdo(this, _permGen->cmsSpace(),
@@ -5753,7 +5813,7 @@
     }
 
     // Now repeat for perm gen
-    if (cms_should_unload_classes()) {
+    if (should_unload_classes()) {
       CMSTokenSyncWithLocks ts(true, _permGen->freelistLock(),
                              bitMapLock());
       sweepWork(_permGen, asynch);
@@ -5775,7 +5835,7 @@
     // already have needed locks
     sweepWork(_cmsGen,  asynch);
 
-    if (cms_should_unload_classes()) {
+    if (should_unload_classes()) {
       sweepWork(_permGen, asynch);
     }
     // Update heap occupancy information which is used as
@@ -5937,6 +5997,11 @@
   }
   gen->cmsSpace()->sweep_completed();
   gen->cmsSpace()->endSweepFLCensus(sweepCount());
+  if (should_unload_classes()) {                // unloaded classes this cycle,
+    _concurrent_cycles_since_last_unload = 0;   // ... reset count
+  } else {                                      // did not unload classes,
+    _concurrent_cycles_since_last_unload++;     // ... increment count
+  }
 }
 
 // Reset CMS data structures (for now just the marking bit map)
@@ -7194,7 +7259,7 @@
   _revisitStack(revisitStack),
   _finger(finger),
   _parent(parent),
-  _should_remember_klasses(collector->cms_should_unload_classes())
+  _should_remember_klasses(collector->should_unload_classes())
 { }
 
 Par_PushOrMarkClosure::Par_PushOrMarkClosure(CMSCollector* collector,
@@ -7217,7 +7282,7 @@
   _finger(finger),
   _global_finger_addr(global_finger_addr),
   _parent(parent),
-  _should_remember_klasses(collector->cms_should_unload_classes())
+  _should_remember_klasses(collector->should_unload_classes())
 { }
 
 
@@ -7360,7 +7425,7 @@
   _mark_stack(mark_stack),
   _revisit_stack(revisit_stack),
   _concurrent_precleaning(concurrent_precleaning),
-  _should_remember_klasses(collector->cms_should_unload_classes())
+  _should_remember_klasses(collector->should_unload_classes())
 {
   assert(_ref_processor != NULL, "_ref_processor shouldn't be NULL");
 }
@@ -7422,7 +7487,7 @@
   _bit_map(bit_map),
   _work_queue(work_queue),
   _revisit_stack(revisit_stack),
-  _should_remember_klasses(collector->cms_should_unload_classes())
+  _should_remember_klasses(collector->should_unload_classes())
 {
   assert(_ref_processor != NULL, "_ref_processor shouldn't be NULL");
 }
@@ -7944,7 +8009,7 @@
 
     #ifdef DEBUG
       if (oop(addr)->klass() != NULL &&
-          (   !_collector->cms_should_unload_classes()
+          (   !_collector->should_unload_classes()
            || oop(addr)->is_parsable())) {
         // Ignore mark word because we are running concurrent with mutators
         assert(oop(addr)->is_oop(true), "live block should be an oop");
@@ -7957,7 +8022,7 @@
   } else {
     // This should be an initialized object that's alive.
     assert(oop(addr)->klass() != NULL &&
-           (!_collector->cms_should_unload_classes()
+           (!_collector->should_unload_classes()
             || oop(addr)->is_parsable()),
            "Should be an initialized object");
     // Ignore mark word because we are running concurrent with mutators
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp	Fri Apr 11 09:56:35 2008 -0400
@@ -535,13 +535,16 @@
   // In support of ExplicitGCInvokesConcurrent
   static   bool _full_gc_requested;
   unsigned int  _collection_count_start;
+
   // Should we unload classes this concurrent cycle?
-  // Set in response to a concurrent full gc request.
-  bool _unload_classes;
-  bool _unloaded_classes_last_cycle;
+  bool _should_unload_classes;
+  unsigned int  _concurrent_cycles_since_last_unload;
+  unsigned int concurrent_cycles_since_last_unload() const {
+    return _concurrent_cycles_since_last_unload;
+  }
   // Did we (allow) unload classes in the previous concurrent cycle?
-  bool cms_unloaded_classes_last_cycle() const {
-    return _unloaded_classes_last_cycle || CMSClassUnloadingEnabled;
+  bool unloaded_classes_last_cycle() const {
+    return concurrent_cycles_since_last_unload() == 0;
   }
 
   // Verification support
@@ -651,8 +654,6 @@
   // number of full gc's since the last concurrent gc.
   uint   _full_gcs_since_conc_gc;
 
-  // if occupancy exceeds this, start a new gc cycle
-  double _initiatingOccupancy;
   // occupancy used for bootstrapping stats
   double _bootstrap_occupancy;
 
@@ -825,7 +826,6 @@
 
   Mutex* bitMapLock()        const { return _markBitMap.lock();    }
   static CollectorState abstract_state() { return _collectorState;  }
-  double initiatingOccupancy() const { return _initiatingOccupancy; }
 
   bool should_abort_preclean() const; // Whether preclean should be aborted.
   size_t get_eden_used() const;
@@ -849,11 +849,10 @@
   // In support of ExplicitGCInvokesConcurrent
   static void request_full_gc(unsigned int full_gc_count);
   // Should we unload classes in a particular concurrent cycle?
-  bool cms_should_unload_classes() const {
-    assert(!_unload_classes ||  ExplicitGCInvokesConcurrentAndUnloadsClasses,
-           "Inconsistency; see CR 6541037");
-    return _unload_classes || CMSClassUnloadingEnabled;
+  bool should_unload_classes() const {
+    return _should_unload_classes;
   }
+  bool update_should_unload_classes();
 
   void direct_allocated(HeapWord* start, size_t size);
 
@@ -1022,6 +1021,10 @@
     _incremental_collection_failed = false;
   }
 
+  // accessors
+  void set_expansion_cause(CMSExpansionCause::Cause v) { _expansion_cause = v;}
+  CMSExpansionCause::Cause expansion_cause() const { return _expansion_cause; }
+
  private:
   // For parallel young-gen GC support.
   CMSParGCThreadState** _par_gc_thread_states;
@@ -1029,10 +1032,6 @@
   // Reason generation was expanded
   CMSExpansionCause::Cause _expansion_cause;
 
-  // accessors
-  void set_expansion_cause(CMSExpansionCause::Cause v) { _expansion_cause = v;}
-  CMSExpansionCause::Cause expansion_cause() { return _expansion_cause; }
-
   // In support of MinChunkSize being larger than min object size
   const double _dilatation_factor;
 
@@ -1045,6 +1044,10 @@
 
   CollectionTypes _debug_collection_type;
 
+  // Fraction of current occupancy at which to start a CMS collection which
+  // will collect this generation (at least).
+  double _initiating_occupancy;
+
  protected:
   // Grow generation by specified size (returns false if unable to grow)
   bool grow_by(size_t bytes);
@@ -1060,6 +1063,10 @@
   // space.
   size_t max_available() const;
 
+  // getter and initializer for _initiating_occupancy field.
+  double initiating_occupancy() const { return _initiating_occupancy; }
+  void   init_initiating_occupancy(intx io, intx tr);
+
  public:
   ConcurrentMarkSweepGeneration(ReservedSpace rs, size_t initial_byte_size,
                                 int level, CardTableRS* ct,
@@ -1103,7 +1110,7 @@
   size_t capacity() const;
   size_t used() const;
   size_t free() const;
-  double occupancy()      { return ((double)used())/((double)capacity()); }
+  double occupancy() const { return ((double)used())/((double)capacity()); }
   size_t contiguous_available() const;
   size_t unsafe_max_alloc_nogc() const;
 
@@ -1158,8 +1165,8 @@
     bool younger_handles_promotion_failure) const;
 
   bool should_collect(bool full, size_t size, bool tlab);
-    // XXXPERM
-  bool shouldConcurrentCollect(double initiatingOccupancy); // XXXPERM
+  virtual bool should_concurrent_collect() const;
+  virtual bool is_too_full() const;
   void collect(bool   full,
                bool   clear_all_soft_refs,
                size_t size,
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.inline.hpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.inline.hpp	Fri Apr 11 09:56:35 2008 -0400
@@ -267,7 +267,7 @@
          (_permGen->cmsSpace()->is_in_reserved(addr)
           && _permGen->cmsSpace()->block_is_obj(addr)),
          "must be object");
-  return  cms_should_unload_classes() &&
+  return  should_unload_classes() &&
           _collectorState == Sweeping &&
          !_markBitMap.isMarked(addr);
 }
--- a/hotspot/src/share/vm/includeDB_compiler1	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/includeDB_compiler1	Fri Apr 11 09:56:35 2008 -0400
@@ -323,7 +323,7 @@
 c1_Runtime1.cpp                         compilationPolicy.hpp
 c1_Runtime1.cpp                         compiledIC.hpp
 c1_Runtime1.cpp                         copy.hpp
-c1_Runtime1.cpp                         disassembler_<arch>.hpp
+c1_Runtime1.cpp                         disassembler.hpp
 c1_Runtime1.cpp                         events.hpp
 c1_Runtime1.cpp                         interfaceSupport.hpp
 c1_Runtime1.cpp                         interpreter.hpp
--- a/hotspot/src/share/vm/includeDB_core	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/includeDB_core	Fri Apr 11 09:56:35 2008 -0400
@@ -244,7 +244,7 @@
 
 assembler.inline.hpp                    assembler.hpp
 assembler.inline.hpp                    codeBuffer.hpp
-assembler.inline.hpp                    disassembler_<arch>.hpp
+assembler.inline.hpp                    disassembler.hpp
 assembler.inline.hpp                    threadLocalStorage.hpp
 
 assembler_<arch_model>.cpp              assembler_<arch_model>.inline.hpp
@@ -946,7 +946,7 @@
 codeBlob.cpp                            bytecode.hpp
 codeBlob.cpp                            codeBlob.hpp
 codeBlob.cpp                            codeCache.hpp
-codeBlob.cpp                            disassembler_<arch>.hpp
+codeBlob.cpp                            disassembler.hpp
 codeBlob.cpp                            forte.hpp
 codeBlob.cpp                            handles.inline.hpp
 codeBlob.cpp                            heap.hpp
@@ -968,7 +968,7 @@
 
 codeBuffer.cpp                          codeBuffer.hpp
 codeBuffer.cpp                          copy.hpp
-codeBuffer.cpp                          disassembler_<arch>.hpp
+codeBuffer.cpp                          disassembler.hpp
 
 codeBuffer.hpp                          assembler.hpp
 codeBuffer.hpp                          oopRecorder.hpp
@@ -1323,7 +1323,7 @@
 debug.cpp                               collectedHeap.hpp
 debug.cpp                               compileBroker.hpp
 debug.cpp                               defaultStream.hpp
-debug.cpp                               disassembler_<arch>.hpp
+debug.cpp                               disassembler.hpp
 debug.cpp                               events.hpp
 debug.cpp                               frame.hpp
 debug.cpp                               heapDumper.hpp
@@ -1442,7 +1442,7 @@
 deoptimization.hpp                      frame.inline.hpp
 
 depChecker_<arch>.cpp                   depChecker_<arch>.hpp
-depChecker_<arch>.cpp                   disassembler_<arch>.hpp
+depChecker_<arch>.cpp                   disassembler.hpp
 depChecker_<arch>.cpp                   hpi.hpp
 
 dependencies.cpp                        ciArrayKlass.hpp
@@ -1472,21 +1472,21 @@
 dictionary.hpp                          oop.hpp
 dictionary.hpp                          systemDictionary.hpp
 
-disassemblerEnv.hpp                     globals.hpp
-
-disassembler_<arch>.cpp                 cardTableModRefBS.hpp
-disassembler_<arch>.cpp                 codeCache.hpp
-disassembler_<arch>.cpp                 collectedHeap.hpp
-disassembler_<arch>.cpp                 depChecker_<arch>.hpp
-disassembler_<arch>.cpp                 disassembler_<arch>.hpp
-disassembler_<arch>.cpp                 fprofiler.hpp
-disassembler_<arch>.cpp                 handles.inline.hpp
-disassembler_<arch>.cpp                 hpi.hpp
-disassembler_<arch>.cpp                 stubCodeGenerator.hpp
-disassembler_<arch>.cpp                 stubRoutines.hpp
-
-disassembler_<arch>.hpp                 disassemblerEnv.hpp
-disassembler_<arch>.hpp                 os_<os_family>.inline.hpp
+disassembler_<arch>.hpp                 generate_platform_dependent_include
+
+disassembler.cpp                        cardTableModRefBS.hpp
+disassembler.cpp                        codeCache.hpp
+disassembler.cpp                        collectedHeap.hpp
+disassembler.cpp                        depChecker_<arch>.hpp
+disassembler.cpp                        disassembler.hpp
+disassembler.cpp                        fprofiler.hpp
+disassembler.cpp                        handles.inline.hpp
+disassembler.cpp                        hpi.hpp
+disassembler.cpp                        stubCodeGenerator.hpp
+disassembler.cpp                        stubRoutines.hpp
+
+disassembler.hpp                        globals.hpp
+disassembler.hpp                        os_<os_family>.inline.hpp
 
 dtraceAttacher.cpp                      codeCache.hpp
 dtraceAttacher.cpp                      deoptimization.hpp
@@ -2909,7 +2909,7 @@
 nmethod.cpp                             compileLog.hpp
 nmethod.cpp                             compiledIC.hpp
 nmethod.cpp                             compilerOracle.hpp
-nmethod.cpp                             disassembler_<arch>.hpp
+nmethod.cpp                             disassembler.hpp
 nmethod.cpp                             dtrace.hpp
 nmethod.cpp                             events.hpp
 nmethod.cpp                             jvmtiRedefineClassesTrace.hpp
@@ -3763,7 +3763,7 @@
 statSampler.hpp                         task.hpp
 
 stubCodeGenerator.cpp                   assembler_<arch_model>.inline.hpp
-stubCodeGenerator.cpp                   disassembler_<arch>.hpp
+stubCodeGenerator.cpp                   disassembler.hpp
 stubCodeGenerator.cpp                   forte.hpp
 stubCodeGenerator.cpp                   oop.inline.hpp
 stubCodeGenerator.cpp                   stubCodeGenerator.hpp
@@ -4530,7 +4530,7 @@
 vmreg_<arch>.hpp                        generate_platform_dependent_include
 
 vtableStubs.cpp                         allocation.inline.hpp
-vtableStubs.cpp                         disassembler_<arch>.hpp
+vtableStubs.cpp                         disassembler.hpp
 vtableStubs.cpp                         forte.hpp
 vtableStubs.cpp                         handles.inline.hpp
 vtableStubs.cpp                         instanceKlass.hpp
--- a/hotspot/src/share/vm/memory/gcLocker.hpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/memory/gcLocker.hpp	Fri Apr 11 09:56:35 2008 -0400
@@ -184,7 +184,9 @@
   Thread *_thread;
  public:
 #ifdef ASSERT
-  No_Safepoint_Verifier(bool activated = true, bool verifygc = true ) : No_GC_Verifier(verifygc) {
+  No_Safepoint_Verifier(bool activated = true, bool verifygc = true ) :
+    No_GC_Verifier(verifygc),
+    _activated(activated) {
     _thread = Thread::current();
     if (_activated) {
       _thread->_allow_allocation_count++;
--- a/hotspot/src/share/vm/oops/methodOop.cpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/oops/methodOop.cpp	Fri Apr 11 09:56:35 2008 -0400
@@ -888,10 +888,11 @@
       symbolHandle name (THREAD, sym);
       klassOop klass = SystemDictionary::resolve_or_null(name, class_loader,
                                              protection_domain, THREAD);
-      // We are loading classes eagerly. If a ClassNotFoundException was generated,
-      // be sure to ignore it.
+      // We are loading classes eagerly. If a ClassNotFoundException or
+      // a LinkageError was generated, be sure to ignore it.
       if (HAS_PENDING_EXCEPTION) {
-        if (PENDING_EXCEPTION->is_a(SystemDictionary::classNotFoundException_klass())) {
+        if (PENDING_EXCEPTION->is_a(SystemDictionary::classNotFoundException_klass()) ||
+            PENDING_EXCEPTION->is_a(SystemDictionary::linkageError_klass())) {
           CLEAR_PENDING_EXCEPTION;
         } else {
           return false;
--- a/hotspot/src/share/vm/opto/addnode.cpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/opto/addnode.cpp	Fri Apr 11 09:56:35 2008 -0400
@@ -70,9 +70,14 @@
 
   // Convert "Load+x" into "x+Load".
   // Now check for loads
-  if( in2->is_Load() ) return false;
-  // Left is a Load and Right is not; move it right.
-  if( in1->is_Load() ) {
+  if (in2->is_Load()) {
+    if (!in1->is_Load()) {
+      // already x+Load to return
+      return false;
+    }
+    // both are loads, so fall through to sort inputs by idx
+  } else if( in1->is_Load() ) {
+    // Left is a Load and Right is not; move it right.
     add->swap_edges(1, 2);
     return true;
   }
--- a/hotspot/src/share/vm/opto/compile.cpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/opto/compile.cpp	Fri Apr 11 09:56:35 2008 -0400
@@ -456,7 +456,15 @@
   }
   TraceTime t1("Total compilation time", &_t_totalCompilation, TimeCompiler, TimeCompiler2);
   TraceTime t2(NULL, &_t_methodCompilation, TimeCompiler, false);
-  set_print_assembly(PrintOptoAssembly || _method->should_print_assembly());
+  bool print_opto_assembly = PrintOptoAssembly || _method->has_option("PrintOptoAssembly");
+  if (!print_opto_assembly) {
+    bool print_assembly = (PrintAssembly || _method->should_print_assembly());
+    if (print_assembly && !Disassembler::can_decode()) {
+      tty->print_cr("PrintAssembly request changed to PrintOptoAssembly");
+      print_opto_assembly = true;
+    }
+  }
+  set_print_assembly(print_opto_assembly);
 #endif
 
   if (ProfileTraps) {
--- a/hotspot/src/share/vm/opto/escape.cpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/opto/escape.cpp	Fri Apr 11 09:56:35 2008 -0400
@@ -256,39 +256,49 @@
   }
 }
 
-void ConnectionGraph::remove_deferred(uint ni) {
-  VectorSet visited(Thread::current()->resource_area());
+void ConnectionGraph::remove_deferred(uint ni, GrowableArray<uint>* deferred_edges, VectorSet* visited) {
+  // This method is most expensive during ConnectionGraph construction.
+  // Reuse vectorSet and an additional growable array for deferred edges.
+  deferred_edges->clear();
+  visited->Clear();
 
   uint i = 0;
   PointsToNode *ptn = ptnode_adr(ni);
 
-  while(i < ptn->edge_count()) {
+  // Mark current edges as visited and move deferred edges to separate array.
+  for (; i < ptn->edge_count(); i++) {
     uint t = ptn->edge_target(i);
-    PointsToNode *ptt = ptnode_adr(t);
-    if (ptn->edge_type(i) != PointsToNode::DeferredEdge) {
-      i++;
-    } else {
+#ifdef ASSERT
+    assert(!visited->test_set(t), "expecting no duplications");
+#else
+    visited->set(t);
+#endif
+    if (ptn->edge_type(i) == PointsToNode::DeferredEdge) {
       ptn->remove_edge(t, PointsToNode::DeferredEdge);
-      if(!visited.test_set(t)) {
-        for (uint j = 0; j < ptt->edge_count(); j++) {
-          uint n1 = ptt->edge_target(j);
-          PointsToNode *pt1 = ptnode_adr(n1);
-          switch(ptt->edge_type(j)) {
-            case PointsToNode::PointsToEdge:
-              add_pointsto_edge(ni, n1);
-              if(n1 == _phantom_object) {
-                // Special case - field set outside (globally escaping).
-                ptn->set_escape_state(PointsToNode::GlobalEscape);
-              }
-              break;
-            case PointsToNode::DeferredEdge:
-              add_deferred_edge(ni, n1);
-              break;
-            case PointsToNode::FieldEdge:
-              assert(false, "invalid connection graph");
-              break;
+      deferred_edges->append(t);
+    }
+  }
+  for (int next = 0; next < deferred_edges->length(); ++next) {
+    uint t = deferred_edges->at(next);
+    PointsToNode *ptt = ptnode_adr(t);
+    for (uint j = 0; j < ptt->edge_count(); j++) {
+      uint n1 = ptt->edge_target(j);
+      if (visited->test_set(n1))
+        continue;
+      switch(ptt->edge_type(j)) {
+        case PointsToNode::PointsToEdge:
+          add_pointsto_edge(ni, n1);
+          if(n1 == _phantom_object) {
+            // Special case - field set outside (globally escaping).
+            ptn->set_escape_state(PointsToNode::GlobalEscape);
           }
-        }
+          break;
+        case PointsToNode::DeferredEdge:
+          deferred_edges->append(n1);
+          break;
+        case PointsToNode::FieldEdge:
+          assert(false, "invalid connection graph");
+          break;
       }
     }
   }
@@ -1243,8 +1253,10 @@
   }
 
   VectorSet ptset(Thread::current()->resource_area());
-  GrowableArray<Node*>  alloc_worklist;
-  GrowableArray<int>  worklist;
+  GrowableArray<Node*> alloc_worklist;
+  GrowableArray<int>   worklist;
+  GrowableArray<uint>  deferred_edges;
+  VectorSet visited(Thread::current()->resource_area());
 
   // remove deferred edges from the graph and collect
   // information we will need for type splitting
@@ -1254,7 +1266,7 @@
     PointsToNode::NodeType nt = ptn->node_type();
     Node *n = ptn->_node;
     if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) {
-      remove_deferred(ni);
+      remove_deferred(ni, &deferred_edges, &visited);
       if (n->is_AddP()) {
         // If this AddP computes an address which may point to more that one
         // object, nothing the address points to can be scalar replaceable.
--- a/hotspot/src/share/vm/opto/escape.hpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/opto/escape.hpp	Fri Apr 11 09:56:35 2008 -0400
@@ -269,7 +269,7 @@
   // Remove outgoing deferred edges from the node referenced by "ni".
   // Any outgoing edges from the target of the deferred edge are copied
   // to "ni".
-  void remove_deferred(uint ni);
+  void remove_deferred(uint ni, GrowableArray<uint>* deferred_edges, VectorSet* visited);
 
   Node_Array _node_map; // used for bookeeping during type splitting
                         // Used for the following purposes:
--- a/hotspot/src/share/vm/opto/loopUnswitch.cpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/opto/loopUnswitch.cpp	Fri Apr 11 09:56:35 2008 -0400
@@ -51,6 +51,9 @@
   if( !LoopUnswitching ) {
     return false;
   }
+  if (!_head->is_Loop()) {
+    return false;
+  }
   uint nodes_left = MaxNodeLimit - phase->C->unique();
   if (2 * _body.size() > nodes_left) {
     return false; // Too speculative if running low on nodes.
--- a/hotspot/src/share/vm/opto/loopopts.cpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/opto/loopopts.cpp	Fri Apr 11 09:56:35 2008 -0400
@@ -2257,6 +2257,9 @@
 //
 bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
 
+  if (!loop->_head->is_Loop()) {
+    return false;  }
+
   LoopNode *head  = loop->_head->as_Loop();
 
   if (head->is_partial_peel_loop() || head->partial_peel_has_failed()) {
--- a/hotspot/src/share/vm/opto/parse3.cpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/opto/parse3.cpp	Fri Apr 11 09:56:35 2008 -0400
@@ -408,7 +408,7 @@
     jint dim_con = find_int_con(length[j], -1);
     expand_fanout *= dim_con;
     expand_count  += expand_fanout; // count the level-J sub-arrays
-    if (dim_con < 0
+    if (dim_con <= 0
         || dim_con > expand_limit
         || expand_count > expand_limit) {
       expand_count = 0;
--- a/hotspot/src/share/vm/opto/superword.cpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/opto/superword.cpp	Fri Apr 11 09:56:35 2008 -0400
@@ -65,6 +65,11 @@
   Node *cl_exit = cl->loopexit();
   if (cl_exit->in(0) != lpt->_head) return;
 
+  // Make sure the are no extra control users of the loop backedge
+  if (cl->back_control()->outcnt() != 1) {
+    return;
+  }
+
   // Check for pre-loop ending with CountedLoopEnd(Bool(Cmp(x,Opaque1(limit))))
   CountedLoopEndNode* pre_end = get_pre_loop_end(cl);
   if (pre_end == NULL) return;
--- a/hotspot/src/share/vm/prims/forte.cpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/prims/forte.cpp	Fri Apr 11 09:56:35 2008 -0400
@@ -25,6 +25,20 @@
 # include "incls/_precompiled.incl"
 # include "incls/_forte.cpp.incl"
 
+// These name match the names reported by the forte quality kit
+enum {
+  ticks_no_Java_frame         =  0,
+  ticks_no_class_load         = -1,
+  ticks_GC_active             = -2,
+  ticks_unknown_not_Java      = -3,
+  ticks_not_walkable_not_Java = -4,
+  ticks_unknown_Java          = -5,
+  ticks_not_walkable_Java     = -6,
+  ticks_unknown_state         = -7,
+  ticks_thread_exit           = -8,
+  ticks_deopt                 = -9,
+  ticks_safepoint             = -10
+};
 
 //-------------------------------------------------------
 
@@ -41,297 +55,29 @@
 };
 
 
-static void forte_is_walkable_compiled_frame(frame* fr, RegisterMap* map,
+static void is_decipherable_compiled_frame(frame* fr, RegisterMap* map,
   bool* is_compiled_p, bool* is_walkable_p);
-static bool forte_is_walkable_interpreted_frame(frame* fr,
-  methodOop* method_p, int* bci_p);
+static bool is_decipherable_interpreted_frame(JavaThread* thread,
+                                                frame* fr,
+                                                methodOop* method_p,
+                                                int* bci_p);
 
 
-// A Forte specific version of frame:safe_for_sender().
-static bool forte_safe_for_sender(frame* fr, JavaThread *thread) {
-  bool ret_value = false;  // be pessimistic
-
-#ifdef COMPILER2
-#if defined(IA32) || defined(AMD64)
-  {
-    // This check is the same as the standard safe_for_sender()
-    // on IA32 or AMD64 except that NULL FP values are tolerated
-    // for C2.
-    address   sp = (address)fr->sp();
-    address   fp = (address)fr->fp();
-    ret_value = sp != NULL && sp <= thread->stack_base() &&
-      sp >= thread->stack_base() - thread->stack_size() &&
-      (fp == NULL || (fp <= thread->stack_base() &&
-      fp >= thread->stack_base() - thread->stack_size()));
-
-    // We used to use standard safe_for_sender() when we are supposed
-    // to be executing Java code. However, that prevents us from
-    // walking some intrinsic stacks so now we have to be more refined.
-    // If we passed the above check and we have a NULL frame pointer
-    // and we are supposed to be executing Java code, then we have a
-    // couple of more checks to make.
-    if (ret_value && fp == NULL && (thread->thread_state() == _thread_in_Java
-        || thread->thread_state() == _thread_in_Java_trans)) {
-
-      if (fr->is_interpreted_frame()) {
-        // interpreted frames don't really have a NULL frame pointer
-        return false;
-      } else if (CodeCache::find_blob(fr->pc()) == NULL) {
-        // the NULL frame pointer should be associated with generated code
-        return false;
-      }
-    }
-  }
-
-#else // !(IA32 || AMD64)
-  ret_value = fr->safe_for_sender(thread);
-#endif // IA32 || AMD64
-
-#else // !COMPILER2
-  ret_value = fr->safe_for_sender(thread);
-#endif // COMPILER2
-
-  if (!ret_value) {
-    return ret_value;  // not safe, nothing more to do
-  }
-
-  address sp1;
-
-#ifdef SPARC
-  // On Solaris SPARC, when a compiler frame has an interpreted callee
-  // the _interpreter_sp_adjustment field contains the adjustment to
-  // this frame's SP made by that interpreted callee.
-  // For AsyncGetCallTrace(), we need to verify that the resulting SP
-  // is valid for the specified thread's stack.
-  sp1 = (address)fr->sp();
-  address sp2 = (address)fr->unextended_sp();
-
-  // If the second SP is NULL, then the _interpreter_sp_adjustment
-  // field simply adjusts this frame's SP to NULL and the frame is
-  // not safe. This strange value can be set in the frame constructor
-  // when our peek into the interpreted callee's adjusted value for
-  // this frame's SP finds a NULL. This can happen when SIGPROF
-  // catches us while we are creating the interpreter frame.
-  //
-  if (sp2 == NULL ||
-
-      // If the two SPs are different, then _interpreter_sp_adjustment
-      // is non-zero and we need to validate the second SP. We invert
-      // the range check from frame::safe_for_sender() and bail out
-      // if the second SP is not safe.
-      (sp1 != sp2 && !(sp2 <= thread->stack_base()
-      && sp2 >= (thread->stack_base() - thread->stack_size())))) {
-    return false;
-  }
-#endif // SPARC
-
-  if (fr->is_entry_frame()) {
-    // This frame thinks it is an entry frame; we need to validate
-    // the JavaCallWrapper pointer.
-    // Note: frame::entry_frame_is_first() assumes that the
-    // JavaCallWrapper has a non-NULL _anchor field. We don't
-    // check that here (yet) since we've never seen a failure
-    // due to a NULL _anchor field.
-    // Update: Originally this check was done only for SPARC. However,
-    // this failure has now been seen on C2 C86. I have no reason to
-    // believe that this is not a general issue so I'm enabling the
-    // check for all compilers on all supported platforms.
-#ifdef COMPILER2
-#if defined(IA32) || defined(AMD64)
-    if (fr->fp() == NULL) {
-      // C2 X86 allows NULL frame pointers, but if we have one then
-      // we cannot call entry_frame_call_wrapper().
-      return false;
-    }
-#endif // IA32 || AMD64
-#endif // COMPILER2
-
-    sp1 = (address)fr->entry_frame_call_wrapper();
-    // We invert the range check from frame::safe_for_sender() and
-    // bail out if the JavaCallWrapper * is not safe.
-    if (!(sp1 <= thread->stack_base()
-        && sp1 >= (thread->stack_base() - thread->stack_size()))) {
-      return false;
-    }
-  }
-
-  return ret_value;
-}
 
 
-// Unknown compiled frames have caused assertion failures on Solaris
-// X86. This code also detects unknown compiled frames on Solaris
-// SPARC, but no assertion failures have been observed. However, I'm
-// paranoid so I'm enabling this code whenever we have a compiler.
-//
-// Returns true if the specified frame is an unknown compiled frame
-// and false otherwise.
-static bool is_unknown_compiled_frame(frame* fr, JavaThread *thread) {
-  bool ret_value = false;  // be optimistic
-
-  // This failure mode only occurs when the thread is in state
-  // _thread_in_Java so we are okay for this check for any other
-  // thread state.
-  //
-  // Note: _thread_in_Java does not always mean that the thread
-  // is executing Java code. AsyncGetCallTrace() has caught
-  // threads executing in JRT_LEAF() routines when the state
-  // will also be _thread_in_Java.
-  if (thread->thread_state() != _thread_in_Java) {
-    return ret_value;
-  }
-
-  // This failure mode only occurs with compiled frames so we are
-  // okay for this check for both entry and interpreted frames.
-  if (fr->is_entry_frame() || fr->is_interpreted_frame()) {
-    return ret_value;
-  }
-
-  // This failure mode only occurs when the compiled frame's PC
-  // is in the code cache so we are okay for this check if the
-  // PC is not in the code cache.
-  CodeBlob* cb = CodeCache::find_blob(fr->pc());
-  if (cb == NULL) {
-    return ret_value;
-  }
+vframeStreamForte::vframeStreamForte(JavaThread *jt,
+                                     frame fr,
+                                     bool stop_at_java_call_stub) : vframeStreamCommon(jt) {
 
-  // We have compiled code in the code cache so it is time for
-  // the final check: let's see if any frame type is set
-  ret_value = !(
-    // is_entry_frame() is checked above
-    // testers that are a subset of is_entry_frame():
-    //   is_first_frame()
-    fr->is_java_frame()
-    // testers that are a subset of is_java_frame():
-    //   is_interpreted_frame()
-    //   is_compiled_frame()
-    || fr->is_native_frame()
-    || fr->is_runtime_frame()
-    || fr->is_safepoint_blob_frame()
-    );
-
-  // If there is no frame type set, then we have an unknown compiled
-  // frame and sender() should not be called on it.
-
-  return ret_value;
-}
-
-#define DebugNonSafepoints_IS_CLEARED \
-  (!FLAG_IS_DEFAULT(DebugNonSafepoints) && !DebugNonSafepoints)
-
-// if -XX:-DebugNonSafepoints, then top-frame will be skipped
-vframeStreamForte::vframeStreamForte(JavaThread *jt, frame fr,
-  bool stop_at_java_call_stub) : vframeStreamCommon(jt) {
   _stop_at_java_call_stub = stop_at_java_call_stub;
-
-  if (!DebugNonSafepoints_IS_CLEARED) {
-    // decode the top frame fully
-    // (usual case, if JVMTI is enabled)
-    _frame = fr;
-  } else {
-    // skip top frame, as it may not be at safepoint
-    // For AsyncGetCallTrace(), we extracted as much info from the top
-    // frame as we could in forte_is_walkable_frame(). We also verified
-    // forte_safe_for_sender() so this sender() call is safe.
-    _frame  = fr.sender(&_reg_map);
-  }
-
-  if (jt->thread_state() == _thread_in_Java && !fr.is_first_frame()) {
-    bool sender_check = false;  // assume sender is not safe
-
-    if (forte_safe_for_sender(&_frame, jt)) {
-      // If the initial sender frame is safe, then continue on with other
-      // checks. The unsafe sender frame has been seen on Solaris X86
-      // with both Compiler1 and Compiler2. It has not been seen on
-      // Solaris SPARC, but seems like a good sanity check to have
-      // anyway.
+  _frame = fr;
 
-      // SIGPROF caught us in Java code and the current frame is not the
-      // first frame so we should sanity check the sender frame. It is
-      // possible for SIGPROF to catch us in the middle of making a call.
-      // When that happens the current frame is actually a combination of
-      // the real sender and some of the new call's info. We can't find
-      // the real sender with such a current frame and things can get
-      // confused.
-      //
-      // This sanity check has caught problems with the sender frame on
-      // Solaris SPARC. So far Solaris X86 has not had a failure here.
-      sender_check = _frame.is_entry_frame()
-        // testers that are a subset of is_entry_frame():
-        //   is_first_frame()
-        || _frame.is_java_frame()
-        // testers that are a subset of is_java_frame():
-        //   is_interpreted_frame()
-        //   is_compiled_frame()
-        || _frame.is_native_frame()
-        || _frame.is_runtime_frame()
-        || _frame.is_safepoint_blob_frame()
-        ;
-
-      // We need an additional sanity check on an initial interpreted
-      // sender frame. This interpreted frame needs to be both walkable
-      // and have a valid BCI. This is yet another variant of SIGPROF
-      // catching us in the middle of making a call.
-      if (sender_check && _frame.is_interpreted_frame()) {
-        methodOop method = NULL;
-        int bci = -1;
-
-        if (!forte_is_walkable_interpreted_frame(&_frame, &method, &bci)
-            || bci == -1) {
-          sender_check = false;
-        }
-      }
-
-      // We need an additional sanity check on an initial compiled
-      // sender frame. This compiled frame also needs to be walkable.
-      // This is yet another variant of SIGPROF catching us in the
-      // middle of making a call.
-      if (sender_check && !_frame.is_interpreted_frame()) {
-        bool is_compiled, is_walkable;
+  // We must always have a valid frame to start filling
 
-        forte_is_walkable_compiled_frame(&_frame, &_reg_map,
-          &is_compiled, &is_walkable);
-        if (is_compiled && !is_walkable) {
-          sender_check = false;
-        }
-      }
-    }
-
-    if (!sender_check) {
-      // nothing else to try if we can't recognize the sender
-      _mode = at_end_mode;
-      return;
-    }
-  }
-
-  int loop_count = 0;
-  int loop_max = MaxJavaStackTraceDepth * 2;
-
-  while (!fill_from_frame()) {
-    _frame = _frame.sender(&_reg_map);
+  bool filled_in = fill_from_frame();
 
-#ifdef COMPILER2
-#if defined(IA32) || defined(AMD64)
-    // Stress testing on C2 X86 has shown a periodic problem with
-    // the sender() call below. The initial _frame that we have on
-    // entry to the loop has already passed forte_safe_for_sender()
-    // so we only check frames after it.
-    if (!forte_safe_for_sender(&_frame, _thread)) {
-      _mode = at_end_mode;
-      return;
-    }
-#endif // IA32 || AMD64
-#endif // COMPILER2
+  assert(filled_in, "invariant");
 
-    if (++loop_count >= loop_max) {
-      // We have looped more than twice the number of possible
-      // Java frames. This indicates that we are trying to walk
-      // a stack that is in the middle of being constructed and
-      // it is self referential.
-      _mode = at_end_mode;
-      return;
-    }
-  }
 }
 
 
@@ -358,95 +104,57 @@
 
   do {
 
-#if defined(COMPILER1) && defined(SPARC)
-  bool prevIsInterpreted =  _frame.is_interpreted_frame();
-#endif // COMPILER1 && SPARC
+    loop_count++;
 
-    _frame = _frame.sender(&_reg_map);
+    // By the time we get here we should never see unsafe but better
+    // safe then segv'd
 
-    if (!forte_safe_for_sender(&_frame, _thread)) {
+    if (loop_count > loop_max || !_frame.safe_for_sender(_thread)) {
       _mode = at_end_mode;
       return;
     }
 
-#if defined(COMPILER1) && defined(SPARC)
-    if (prevIsInterpreted) {
-      // previous callee was interpreted and may require a special check
-      if (_frame.is_compiled_frame() && _frame.cb()->is_compiled_by_c1()) {
-        // compiled sender called interpreted callee so need one more check
-        bool is_compiled, is_walkable;
+    _frame = _frame.sender(&_reg_map);
 
-        // sanity check the compiled sender frame
-        forte_is_walkable_compiled_frame(&_frame, &_reg_map,
-          &is_compiled, &is_walkable);
-        assert(is_compiled, "sanity check");
-        if (!is_walkable) {
-          // compiled sender frame is not walkable so bail out
-          _mode = at_end_mode;
-          return;
-        }
-      }
-    }
-#endif // COMPILER1 && SPARC
-
-    if (++loop_count >= loop_max) {
-      // We have looped more than twice the number of possible
-      // Java frames. This indicates that we are trying to walk
-      // a stack that is in the middle of being constructed and
-      // it is self referential.
-      _mode = at_end_mode;
-      return;
-    }
   } while (!fill_from_frame());
 }
 
-// Determine if 'fr' is a walkable, compiled frame.
-// *is_compiled_p is set to true if the frame is compiled and if it
-// is, then *is_walkable_p is set to true if it is also walkable.
-static void forte_is_walkable_compiled_frame(frame* fr, RegisterMap* map,
-  bool* is_compiled_p, bool* is_walkable_p) {
+// Determine if 'fr' is a decipherable compiled frame. We are already
+// assured that fr is for a java nmethod.
+
+static bool is_decipherable_compiled_frame(frame* fr) {
 
-  *is_compiled_p = false;
-  *is_walkable_p = false;
+  assert(fr->cb() != NULL && fr->cb()->is_nmethod(), "invariant");
+  nmethod* nm = (nmethod*) fr->cb();
+  assert(nm->is_java_method(), "invariant");
+
+  // First try and find an exact PcDesc
 
-  CodeBlob* cb = CodeCache::find_blob(fr->pc());
-  if (cb != NULL &&
-      cb->is_nmethod() &&
-      ((nmethod*)cb)->is_java_method()) {
-    // frame is compiled and executing a Java method
-    *is_compiled_p = true;
+  PcDesc* pc_desc = nm->pc_desc_at(fr->pc());
+
+  // Did we find a useful PcDesc?
+  if (pc_desc != NULL &&
+      pc_desc->scope_decode_offset() == DebugInformationRecorder::serialized_null) {
 
-    // Increment PC because the PcDesc we want is associated with
-    // the *end* of the instruction, and pc_desc_near searches
-    // forward to the first matching PC after the probe PC.
-    PcDesc* pc_desc = NULL;
-    if (!DebugNonSafepoints_IS_CLEARED) {
-      // usual case:  look for any safepoint near the sampled PC
-      address probe_pc = fr->pc() + 1;
-      pc_desc = ((nmethod*) cb)->pc_desc_near(probe_pc);
-    } else {
-      // reduced functionality:  only recognize PCs immediately after calls
-      pc_desc = ((nmethod*) cb)->pc_desc_at(fr->pc());
-    }
-    if (pc_desc != NULL && (pc_desc->scope_decode_offset()
-                            == DebugInformationRecorder::serialized_null)) {
-      pc_desc = NULL;
+    address probe_pc = fr->pc() + 1;
+    pc_desc = nm->pc_desc_near(probe_pc);
+
+    // Now do we have a useful PcDesc?
+
+    if (pc_desc != NULL &&
+        pc_desc->scope_decode_offset() == DebugInformationRecorder::serialized_null) {
+      // No debug information available for this pc
+      // vframeStream would explode if we try and walk the frames.
+      return false;
     }
-    if (pc_desc != NULL) {
-      // it has a PcDesc so the frame is also walkable
-      *is_walkable_p = true;
-      if (!DebugNonSafepoints_IS_CLEARED) {
-        // Normalize the PC to the one associated exactly with
-        // this PcDesc, so that subsequent stack-walking queries
-        // need not be approximate:
-        fr->set_pc(pc_desc->real_pc((nmethod*) cb));
-      }
-    }
-    // Implied else: this compiled frame has no PcDesc, i.e., contains
-    // a frameless stub such as C1 method exit, so it is not walkable.
+
+    // This PcDesc is useful however we must adjust the frame's pc
+    // so that the vframeStream lookups will use this same pc
+
+    fr->set_pc(pc_desc->real_pc(nm));
   }
-  // Implied else: this isn't a compiled frame so it isn't a
-  // walkable, compiled frame.
+
+  return true;
 }
 
 // Determine if 'fr' is a walkable interpreted frame. Returns false
@@ -457,159 +165,189 @@
 // Note: this method returns true when a valid Java method is found
 // even if a valid BCI cannot be found.
 
-static bool forte_is_walkable_interpreted_frame(frame* fr,
-  methodOop* method_p, int* bci_p) {
+static bool is_decipherable_interpreted_frame(JavaThread* thread,
+                                                frame* fr,
+                                                methodOop* method_p,
+                                                int* bci_p) {
   assert(fr->is_interpreted_frame(), "just checking");
 
   // top frame is an interpreted frame
   // check if it is walkable (i.e. valid methodOop and valid bci)
-  if (fr->is_interpreted_frame_valid()) {
-    if (fr->fp() != NULL) {
-      // access address in order not to trigger asserts that
-      // are built in interpreter_frame_method function
-      methodOop method = *fr->interpreter_frame_method_addr();
-      if (Universe::heap()->is_valid_method(method)) {
-        intptr_t bcx = fr->interpreter_frame_bcx();
-        int      bci = method->validate_bci_from_bcx(bcx);
-        // note: bci is set to -1 if not a valid bci
-        *method_p = method;
-        *bci_p = bci;
-        return true;
-      }
-    }
+
+  // Because we may be racing a gc thread the method and/or bci
+  // of a valid interpreter frame may look bad causing us to
+  // fail the is_interpreted_frame_valid test. If the thread
+  // is in any of the following states we are assured that the
+  // frame is in fact valid and we must have hit the race.
+
+  JavaThreadState state = thread->thread_state();
+  bool known_valid = (state == _thread_in_native ||
+                      state == _thread_in_vm ||
+                      state == _thread_blocked );
+
+  if (known_valid || fr->is_interpreted_frame_valid(thread)) {
+
+    // The frame code should completely validate the frame so that
+    // references to methodOop and bci are completely safe to access
+    // If they aren't the frame code should be fixed not this
+    // code. However since gc isn't locked out the values could be
+    // stale. This is a race we can never completely win since we can't
+    // lock out gc so do one last check after retrieving their values
+    // from the frame for additional safety
+
+    methodOop method = fr->interpreter_frame_method();
+
+    // We've at least found a method.
+    // NOTE: there is something to be said for the approach that
+    // if we don't find a valid bci then the method is not likely
+    // a valid method. Then again we may have caught an interpreter
+    // frame in the middle of construction and the bci field is
+    // not yet valid.
+
+    *method_p = method;
+
+    // See if gc may have invalidated method since we validated frame
+
+    if (!Universe::heap()->is_valid_method(method)) return false;
+
+    intptr_t bcx = fr->interpreter_frame_bcx();
+
+    int      bci = method->validate_bci_from_bcx(bcx);
+
+    // note: bci is set to -1 if not a valid bci
+    *bci_p = bci;
+    return true;
   }
+
   return false;
 }
 
 
-// Determine if 'fr' can be used to find a walkable frame. Returns
-// false if a walkable frame cannot be found. *walkframe_p, *method_p,
-// and *bci_p are not set when false is returned. Returns true if a
-// walkable frame is returned via *walkframe_p. *method_p is non-NULL
-// if the returned frame was executing a Java method. *bci_p is != -1
-// if a valid BCI in the Java method could be found.
+// Determine if 'fr' can be used to find an initial Java frame.
+// Return false if it can not find a fully decipherable Java frame
+// (in other words a frame that isn't safe to use in a vframe stream).
+// Obviously if it can't even find a Java frame false will also be returned.
+//
+// If we find a Java frame decipherable or not then by definition we have
+// identified a method and that will be returned to the caller via method_p.
+// If we can determine a bci that is returned also. (Hmm is it possible
+// to return a method and bci and still return false? )
+//
+// The initial Java frame we find (if any) is return via initial_frame_p.
 //
-// *walkframe_p will be used by vframeStreamForte as the initial
-// frame for walking the stack. Currently the initial frame is
-// skipped by vframeStreamForte because we inherited the logic from
-// the vframeStream class. This needs to be revisited in the future.
-static bool forte_is_walkable_frame(JavaThread* thread, frame* fr,
-  frame* walkframe_p, methodOop* method_p, int* bci_p) {
+
+static bool find_initial_Java_frame(JavaThread* thread,
+                                    frame* fr,
+                                    frame* initial_frame_p,
+                                    methodOop* method_p,
+                                    int* bci_p) {
+
+  // It is possible that for a frame containing an nmethod
+  // we can capture the method but no bci. If we get no
+  // bci the frame isn't walkable but the method is usable.
+  // Therefore we init the returned methodOop to NULL so the
+  // caller can make the distinction.
+
+  *method_p = NULL;
+
+  // On the initial call to this method the frame we get may not be
+  // recognizable to us. This should only happen if we are in a JRT_LEAF
+  // or something called by a JRT_LEAF method.
+
 
-  if (!forte_safe_for_sender(fr, thread)
-      || is_unknown_compiled_frame(fr, thread)
-     ) {
-    // If the initial frame is not safe, then bail out. So far this
-    // has only been seen on Solaris X86 with Compiler2, but it seems
-    // like a great initial sanity check.
-    return false;
+
+  frame candidate = *fr;
+
+  // If the starting frame we were given has no codeBlob associated with
+  // it see if we can find such a frame because only frames with codeBlobs
+  // are possible Java frames.
+
+  if (fr->cb() == NULL) {
+
+    // See if we can find a useful frame
+    int loop_count;
+    int loop_max = MaxJavaStackTraceDepth * 2;
+    RegisterMap map(thread, false);
+
+    for (loop_count = 0; loop_count < loop_max; loop_count++) {
+      if (!candidate.safe_for_sender(thread)) return false;
+      candidate = candidate.sender(&map);
+      if (candidate.cb() != NULL) break;
+    }
+    if (candidate.cb() == NULL) return false;
   }
 
-  if (fr->is_first_frame()) {
-    // If initial frame is frame from StubGenerator and there is no
-    // previous anchor, there are no java frames yet
-    return false;
-  }
-
-  if (fr->is_interpreted_frame()) {
-    if (forte_is_walkable_interpreted_frame(fr, method_p, bci_p)) {
-      *walkframe_p = *fr;
-      return true;
-    }
-    return false;
-  }
-
-  // At this point we have something other than a first frame or an
-  // interpreted frame.
-
-  methodOop method = NULL;
-  frame candidate = *fr;
-
-  // If we loop more than twice the number of possible Java
-  // frames, then this indicates that we are trying to walk
-  // a stack that is in the middle of being constructed and
-  // it is self referential. So far this problem has only
-  // been seen on Solaris X86 Compiler2, but it seems like
-  // a good robustness fix for all platforms.
-
+  // We have a frame known to be in the codeCache
+  // We will hopefully be able to figure out something to do with it.
   int loop_count;
   int loop_max = MaxJavaStackTraceDepth * 2;
+  RegisterMap map(thread, false);
 
   for (loop_count = 0; loop_count < loop_max; loop_count++) {
-    // determine if the candidate frame is executing a Java method
-    if (CodeCache::contains(candidate.pc())) {
-      // candidate is a compiled frame or stub routine
-      CodeBlob* cb = CodeCache::find_blob(candidate.pc());
 
-      if (cb->is_nmethod()) {
-        method = ((nmethod *)cb)->method();
-      }
-    } // end if CodeCache has our PC
-
-    RegisterMap map(thread, false);
+    if (candidate.is_first_frame()) {
+      // If initial frame is frame from StubGenerator and there is no
+      // previous anchor, there are no java frames associated with a method
+      return false;
+    }
 
-    // we have a Java frame that seems reasonable
-    if (method != NULL && candidate.is_java_frame()
-        && candidate.sp() != NULL && candidate.pc() != NULL) {
-      // we need to sanity check the candidate further
-      bool is_compiled, is_walkable;
+    if (candidate.is_interpreted_frame()) {
+      if (is_decipherable_interpreted_frame(thread, &candidate, method_p, bci_p)) {
+        *initial_frame_p = candidate;
+        return true;
+      }
 
-      forte_is_walkable_compiled_frame(&candidate, &map, &is_compiled,
-        &is_walkable);
-      if (is_compiled) {
-        // At this point, we know we have a compiled Java frame with
-        // method information that we want to return. We don't check
-        // the is_walkable flag here because that flag pertains to
-        // vframeStreamForte work that is done after we are done here.
-        break;
-      }
+      // Hopefully we got some data
+      return false;
     }
 
-    // At this point, the candidate doesn't work so try the sender.
+    if (candidate.cb()->is_nmethod()) {
+
+      nmethod* nm = (nmethod*) candidate.cb();
+      *method_p = nm->method();
 
-    // For AsyncGetCallTrace() we cannot assume there is a sender
-    // for the initial frame. The initial forte_safe_for_sender() call
-    // and check for is_first_frame() is done on entry to this method.
-    candidate = candidate.sender(&map);
-    if (!forte_safe_for_sender(&candidate, thread)) {
+      // If the frame isn't fully decipherable then the default
+      // value for the bci is a signal that we don't have a bci.
+      // If we have a decipherable frame this bci value will
+      // not be used.
+
+      *bci_p = -1;
 
-#ifdef COMPILER2
-#if defined(IA32) || defined(AMD64)
-      // C2 on X86 can use the ebp register as a general purpose register
-      // which can cause the candidate to fail theforte_safe_for_sender()
-      // above. We try one more time using a NULL frame pointer (fp).
+      *initial_frame_p = candidate;
+
+      // Native wrapper code is trivial to decode by vframeStream
+
+      if (nm->is_native_method()) return true;
 
-      candidate = frame(candidate.sp(), NULL, candidate.pc());
-      if (!forte_safe_for_sender(&candidate, thread)) {
-#endif // IA32 || AMD64
-#endif // COMPILER2
+      // If it isn't decipherable then we have found a pc that doesn't
+      // have a PCDesc that can get us a bci however we did find
+      // a method
 
+      if (!is_decipherable_compiled_frame(&candidate)) {
         return false;
+      }
 
-#ifdef COMPILER2
-#if defined(IA32) || defined(AMD64)
-      } // end forte_safe_for_sender retry with NULL fp
-#endif // IA32 || AMD64
-#endif // COMPILER2
+      // is_decipherable_compiled_frame may modify candidate's pc
+      *initial_frame_p = candidate;
 
-    } // end first forte_safe_for_sender check
+      return true;
+    }
+
+    // Must be some stub frame that we don't care about
 
-    if (candidate.is_first_frame()
-        || is_unknown_compiled_frame(&candidate, thread)) {
-      return false;
-    }
-  } // end for loop_count
+    if (!candidate.safe_for_sender(thread)) return false;
+    candidate = candidate.sender(&map);
 
-  if (method == NULL) {
-    // If we didn't get any method info from the candidate, then
-    // we have nothing to return so bail out.
-    return false;
+    // If it isn't in the code cache something is wrong
+    // since once we find a frame in the code cache they
+    // all should be there.
+
+    if (candidate.cb() == NULL) return false;
+
   }
 
-  *walkframe_p = candidate;
-  *method_p = method;
-  *bci_p = -1;
-  return true;
+  return false;
+
 }
 
 
@@ -627,10 +365,12 @@
 } ASGCT_CallTrace;
 
 static void forte_fill_call_trace_given_top(JavaThread* thd,
-  ASGCT_CallTrace* trace, int depth, frame top_frame) {
+                                            ASGCT_CallTrace* trace,
+                                            int depth,
+                                            frame top_frame) {
   NoHandleMark nhm;
 
-  frame walkframe;
+  frame initial_Java_frame;
   methodOop method;
   int bci;
   int count;
@@ -638,48 +378,51 @@
   count = 0;
   assert(trace->frames != NULL, "trace->frames must be non-NULL");
 
-  if (!forte_is_walkable_frame(thd, &top_frame, &walkframe, &method, &bci)) {
-    // return if no walkable frame is found
-    return;
-  }
+  bool fully_decipherable = find_initial_Java_frame(thd, &top_frame, &initial_Java_frame, &method, &bci);
+
+  // The frame might not be walkable but still recovered a method
+  // (e.g. an nmethod with no scope info for the pc
+
+  if (method == NULL) return;
 
   CollectedHeap* ch = Universe::heap();
 
-  if (method != NULL) {
-    // The method is not stored GC safe so see if GC became active
-    // after we entered AsyncGetCallTrace() and before we try to
-    // use the methodOop.
-    // Yes, there is still a window after this check and before
-    // we use methodOop below, but we can't lock out GC so that
-    // has to be an acceptable risk.
-    if (!ch->is_valid_method(method)) {
-      trace->num_frames = -2;
-      return;
-    }
-
-    if (DebugNonSafepoints_IS_CLEARED) {
-      // Take whatever method the top-frame decoder managed to scrape up.
-      // We look further at the top frame only if non-safepoint
-      // debugging information is available.
-      count++;
-      trace->num_frames = count;
-      trace->frames[0].method_id = method->find_jmethod_id_or_null();
-      if (!method->is_native()) {
-        trace->frames[0].lineno = bci;
-      } else {
-        trace->frames[0].lineno = -3;
-      }
-    }
-  }
-
-  // check has_last_Java_frame() after looking at the top frame
-  // which may be an interpreted Java frame.
-  if (!thd->has_last_Java_frame() && method == NULL) {
-    trace->num_frames = 0;
+  // The method is not stored GC safe so see if GC became active
+  // after we entered AsyncGetCallTrace() and before we try to
+  // use the methodOop.
+  // Yes, there is still a window after this check and before
+  // we use methodOop below, but we can't lock out GC so that
+  // has to be an acceptable risk.
+  if (!ch->is_valid_method(method)) {
+    trace->num_frames = ticks_GC_active; // -2
     return;
   }
 
-  vframeStreamForte st(thd, walkframe, false);
+  // We got a Java frame however it isn't fully decipherable
+  // so it won't necessarily be safe to use it for the
+  // initial frame in the vframe stream.
+
+  if (!fully_decipherable) {
+    // Take whatever method the top-frame decoder managed to scrape up.
+    // We look further at the top frame only if non-safepoint
+    // debugging information is available.
+    count++;
+    trace->num_frames = count;
+    trace->frames[0].method_id = method->find_jmethod_id_or_null();
+    if (!method->is_native()) {
+      trace->frames[0].lineno = bci;
+    } else {
+      trace->frames[0].lineno = -3;
+    }
+
+    if (!initial_Java_frame.safe_for_sender(thd)) return;
+
+    RegisterMap map(thd, false);
+    initial_Java_frame = initial_Java_frame.sender(&map);
+  }
+
+  vframeStreamForte st(thd, initial_Java_frame, false);
+
   for (; !st.at_end() && count < depth; st.forte_next(), count++) {
     bci = st.bci();
     method = st.method();
@@ -693,7 +436,7 @@
     if (!ch->is_valid_method(method)) {
       // we throw away everything we've gathered in this sample since
       // none of it is safe
-      trace->num_frames = -2;
+      trace->num_frames = ticks_GC_active; // -2
       return;
     }
 
@@ -765,6 +508,11 @@
 
 extern "C" {
 void AsyncGetCallTrace(ASGCT_CallTrace *trace, jint depth, void* ucontext) {
+
+// This is if'd out because we no longer use thread suspension.
+// However if someone wanted to backport this to a 5.0 jvm then this
+// code would be important.
+#if 0
   if (SafepointSynchronize::is_synchronizing()) {
     // The safepoint mechanism is trying to synchronize all the threads.
     // Since this can involve thread suspension, it is not safe for us
@@ -774,9 +522,10 @@
     // are suspended while holding a resource and another thread blocks
     // on that resource in the SIGPROF handler, then we will have a
     // three-thread deadlock (VMThread, this thread, the other thread).
-    trace->num_frames = -10;
+    trace->num_frames = ticks_safepoint; // -10
     return;
   }
+#endif
 
   JavaThread* thread;
 
@@ -785,13 +534,13 @@
     thread->is_exiting()) {
 
     // bad env_id, thread has exited or thread is exiting
-    trace->num_frames = -8;
+    trace->num_frames = ticks_thread_exit; // -8
     return;
   }
 
   if (thread->in_deopt_handler()) {
     // thread is in the deoptimization handler so return no frames
-    trace->num_frames = -9;
+    trace->num_frames = ticks_deopt; // -9
     return;
   }
 
@@ -799,12 +548,12 @@
          "AsyncGetCallTrace must be called by the current interrupted thread");
 
   if (!JvmtiExport::should_post_class_load()) {
-    trace->num_frames = -1;
+    trace->num_frames = ticks_no_class_load; // -1
     return;
   }
 
   if (Universe::heap()->is_gc_active()) {
-    trace->num_frames = -2;
+    trace->num_frames = ticks_GC_active; // -2
     return;
   }
 
@@ -827,14 +576,22 @@
 
       // param isInJava == false - indicate we aren't in Java code
       if (!thread->pd_get_top_frame_for_signal_handler(&fr, ucontext, false)) {
+        trace->num_frames = ticks_unknown_not_Java;  // -3 unknown frame
+      } else {
         if (!thread->has_last_Java_frame()) {
-          trace->num_frames = 0;   // no Java frames
+          trace->num_frames = 0; // No Java frames
         } else {
-          trace->num_frames = -3;  // unknown frame
+          trace->num_frames = ticks_not_walkable_not_Java;    // -4 non walkable frame by default
+          forte_fill_call_trace_given_top(thread, trace, depth, fr);
+
+          // This assert would seem to be valid but it is not.
+          // It would be valid if we weren't possibly racing a gc
+          // thread. A gc thread can make a valid interpreted frame
+          // look invalid. It's a small window but it does happen.
+          // The assert is left here commented out as a reminder.
+          // assert(trace->num_frames != ticks_not_walkable_not_Java, "should always be walkable");
+
         }
-      } else {
-        trace->num_frames = -4;    // non walkable frame by default
-        forte_fill_call_trace_given_top(thread, trace, depth, fr);
       }
     }
     break;
@@ -845,16 +602,16 @@
 
       // param isInJava == true - indicate we are in Java code
       if (!thread->pd_get_top_frame_for_signal_handler(&fr, ucontext, true)) {
-        trace->num_frames = -5;  // unknown frame
+        trace->num_frames = ticks_unknown_Java;  // -5 unknown frame
       } else {
-        trace->num_frames = -6;  // non walkable frame by default
+        trace->num_frames = ticks_not_walkable_Java;  // -6, non walkable frame by default
         forte_fill_call_trace_given_top(thread, trace, depth, fr);
       }
     }
     break;
   default:
     // Unknown thread state
-    trace->num_frames = -7;
+    trace->num_frames = ticks_unknown_state; // -7
     break;
   }
 }
--- a/hotspot/src/share/vm/runtime/fprofiler.cpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/runtime/fprofiler.cpp	Fri Apr 11 09:56:35 2008 -0400
@@ -924,29 +924,23 @@
   FlatProfiler::record_thread_ticks();
 }
 
-void ThreadProfiler::record_interpreted_tick(frame fr, TickPosition where, int* ticks) {
+void ThreadProfiler::record_interpreted_tick(JavaThread* thread, frame fr, TickPosition where, int* ticks) {
   FlatProfiler::all_int_ticks++;
   if (!FlatProfiler::full_profile()) {
     return;
   }
 
-  if (!fr.is_interpreted_frame_valid()) {
+  if (!fr.is_interpreted_frame_valid(thread)) {
     // tick came at a bad time
     interpreter_ticks += 1;
     FlatProfiler::interpreter_ticks += 1;
     return;
   }
 
-  methodOop method = NULL;
-  if (fr.fp() != NULL) {
-    method = *fr.interpreter_frame_method_addr();
-  }
-  if (!Universe::heap()->is_valid_method(method)) {
-    // tick came at a bad time, stack frame not initialized correctly
-    interpreter_ticks += 1;
-    FlatProfiler::interpreter_ticks += 1;
-    return;
-  }
+  // The frame has been fully validated so we can trust the method and bci
+
+  methodOop method = *fr.interpreter_frame_method_addr();
+
   interpreted_update(method, where);
 
   // update byte code table
@@ -997,7 +991,7 @@
   // The tick happend in real code -> non VM code
   if (fr.is_interpreted_frame()) {
     interval_data_ref()->inc_interpreted();
-    record_interpreted_tick(fr, tp_code, FlatProfiler::bytecode_ticks);
+    record_interpreted_tick(thread, fr, tp_code, FlatProfiler::bytecode_ticks);
     return;
   }
 
@@ -1028,7 +1022,7 @@
   // The tick happend in VM code
   interval_data_ref()->inc_native();
   if (fr.is_interpreted_frame()) {
-    record_interpreted_tick(fr, tp_native, FlatProfiler::bytecode_ticks_stub);
+    record_interpreted_tick(thread, fr, tp_native, FlatProfiler::bytecode_ticks_stub);
     return;
   }
   if (CodeCache::contains(fr.pc())) {
--- a/hotspot/src/share/vm/runtime/fprofiler.hpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/runtime/fprofiler.hpp	Fri Apr 11 09:56:35 2008 -0400
@@ -135,7 +135,7 @@
   ProfilerNode** table;
 
 private:
-  void record_interpreted_tick(frame fr, TickPosition where, int* ticks);
+  void record_interpreted_tick(JavaThread* thread, frame fr, TickPosition where, int* ticks);
   void record_compiled_tick   (JavaThread* thread, frame fr, TickPosition where);
   void interpreted_update(methodOop method, TickPosition where);
   void compiled_update   (methodOop method, TickPosition where);
--- a/hotspot/src/share/vm/runtime/frame.hpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/runtime/frame.hpp	Fri Apr 11 09:56:35 2008 -0400
@@ -108,7 +108,7 @@
   bool is_first_frame() const; // oldest frame? (has no sender)
   bool is_first_java_frame() const;              // same for Java frame
 
-  bool is_interpreted_frame_valid() const;       // performs sanity checks on interpreted frames.
+  bool is_interpreted_frame_valid(JavaThread* thread) const;       // performs sanity checks on interpreted frames.
 
   // tells whether this frame is marked for deoptimization
   bool should_be_deoptimized() const;
--- a/hotspot/src/share/vm/runtime/globals.cpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/runtime/globals.cpp	Fri Apr 11 09:56:35 2008 -0400
@@ -68,18 +68,20 @@
   if (is_uintx()) st->print("%-16lu", get_uintx());
   if (is_ccstr()) {
     const char* cp = get_ccstr();
-    const char* eol;
-    while ((eol = strchr(cp, '\n')) != NULL) {
-      char format_buffer[FORMAT_BUFFER_LEN];
-      size_t llen = pointer_delta(eol, cp, sizeof(char));
-      jio_snprintf(format_buffer, FORMAT_BUFFER_LEN,
-                   "%%." SIZE_FORMAT "s", llen);
-      st->print(format_buffer, cp);
-      st->cr();
-      cp = eol+1;
-      st->print("%5s %-35s += ", "", name);
+    if (cp != NULL) {
+      const char* eol;
+      while ((eol = strchr(cp, '\n')) != NULL) {
+        char format_buffer[FORMAT_BUFFER_LEN];
+        size_t llen = pointer_delta(eol, cp, sizeof(char));
+        jio_snprintf(format_buffer, FORMAT_BUFFER_LEN,
+                     "%%." SIZE_FORMAT "s", llen);
+        st->print(format_buffer, cp);
+        st->cr();
+        cp = eol+1;
+        st->print("%5s %-35s += ", "", name);
+      }
+      st->print("%-16s", cp);
     }
-    st->print("%-16s", cp);
   }
   st->print(" %s", kind);
   st->cr();
@@ -94,18 +96,21 @@
     st->print("-XX:%s=" UINTX_FORMAT, name, get_uintx());
   } else if (is_ccstr()) {
     st->print("-XX:%s=", name);
-    // Need to turn embedded '\n's back into separate arguments
-    // Not so efficient to print one character at a time,
-    // but the choice is to do the transformation to a buffer
-    // and print that.  And this need not be efficient.
-    for (const char* cp = get_ccstr(); *cp != '\0'; cp += 1) {
-      switch (*cp) {
-      default:
-        st->print("%c", *cp);
-        break;
-      case '\n':
-        st->print(" -XX:%s=", name);
-        break;
+    const char* cp = get_ccstr();
+    if (cp != NULL) {
+      // Need to turn embedded '\n's back into separate arguments
+      // Not so efficient to print one character at a time,
+      // but the choice is to do the transformation to a buffer
+      // and print that.  And this need not be efficient.
+      for (; *cp != '\0'; cp += 1) {
+        switch (*cp) {
+          default:
+            st->print("%c", *cp);
+            break;
+          case '\n':
+            st->print(" -XX:%s=", name);
+            break;
+        }
       }
     }
   } else {
--- a/hotspot/src/share/vm/runtime/globals.hpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/runtime/globals.hpp	Fri Apr 11 09:56:35 2008 -0400
@@ -668,16 +668,19 @@
   notproduct(bool, PrintCompilation2, false,                                \
           "Print additional statistics per compilation")                    \
                                                                             \
-  notproduct(bool, PrintAdapterHandlers, false,                             \
+  diagnostic(bool, PrintAdapterHandlers, false,                             \
           "Print code generated for i2c/c2i adapters")                      \
                                                                             \
-  develop(bool, PrintAssembly, false,                                       \
-          "Print assembly code")                                            \
-                                                                            \
-  develop(bool, PrintNMethods, false,                                       \
+  diagnostic(bool, PrintAssembly, false,                                    \
+          "Print assembly code (using external disassembler.so)")           \
+                                                                            \
+  diagnostic(ccstr, PrintAssemblyOptions, false,                            \
+          "Options string passed to disassembler.so")                       \
+                                                                            \
+  diagnostic(bool, PrintNMethods, false,                                    \
           "Print assembly code for nmethods when generated")                \
                                                                             \
-  develop(bool, PrintNativeNMethods, false,                                 \
+  diagnostic(bool, PrintNativeNMethods, false,                              \
           "Print assembly code for native nmethods when generated")         \
                                                                             \
   develop(bool, PrintDebugInfo, false,                                      \
@@ -702,7 +705,7 @@
   develop(bool, PrintCodeCache2, false,                                     \
           "Print detailed info on the compiled_code cache when exiting")    \
                                                                             \
-  develop(bool, PrintStubCode, false,                                       \
+  diagnostic(bool, PrintStubCode, false,                                    \
           "Print generated stub code")                                      \
                                                                             \
   product(bool, StackTraceInThrowable, true,                                \
@@ -1319,6 +1322,10 @@
   product(bool, CMSClassUnloadingEnabled, false,                            \
           "Whether class unloading enabled when using CMS GC")              \
                                                                             \
+  product(uintx, CMSClassUnloadingMaxInterval, 0,                           \
+          "When CMS class unloading is enabled, the maximum CMS cycle count"\
+          " for which classes may not be unloaded")                         \
+                                                                            \
   product(bool, CMSCompactWhenClearAllSoftRefs, true,                       \
           "Compact when asked to collect CMS gen with clear_all_soft_refs") \
                                                                             \
@@ -1504,17 +1511,30 @@
           "Percentage of MinHeapFreeRatio in CMS generation that is "       \
           "  allocated before a CMS collection cycle commences")            \
                                                                             \
-  product(intx, CMSBootstrapOccupancy, 50,                                  \
+  product(intx, CMSTriggerPermRatio, 80,                                    \
+          "Percentage of MinHeapFreeRatio in the CMS perm generation that"  \
+          "  is allocated before a CMS collection cycle commences, that  "  \
+          "  also collects the perm generation")                            \
+                                                                            \
+  product(uintx, CMSBootstrapOccupancy, 50,                                 \
           "Percentage CMS generation occupancy at which to "                \
           " initiate CMS collection for bootstrapping collection stats")    \
                                                                             \
   product(intx, CMSInitiatingOccupancyFraction, -1,                         \
           "Percentage CMS generation occupancy to start a CMS collection "  \
-          " cycle (A negative value means that CMSTirggerRatio is used)")   \
+          " cycle (A negative value means that CMSTriggerRatio is used)")   \
+                                                                            \
+  product(intx, CMSInitiatingPermOccupancyFraction, -1,                     \
+          "Percentage CMS perm generation occupancy to start a CMScollection"\
+          " cycle (A negative value means that CMSTriggerPermRatio is used)")\
                                                                             \
   product(bool, UseCMSInitiatingOccupancyOnly, false,                       \
           "Only use occupancy as a crierion for starting a CMS collection") \
                                                                             \
+  product(intx, CMSIsTooFullPercentage, 98,                                 \
+          "An absolute ceiling above which CMS will always consider the"    \
+          " perm gen ripe for collection")                                  \
+                                                                            \
   develop(bool, CMSTestInFreeList, false,                                   \
           "Check if the coalesced range is already in the "                 \
           "free lists as claimed.")                                         \
@@ -2250,7 +2270,7 @@
   product_pd(bool, RewriteFrequentPairs,                                    \
           "Rewrite frequently used bytecode pairs into a single bytecode")  \
                                                                             \
-  product(bool, PrintInterpreter, false,                                    \
+  diagnostic(bool, PrintInterpreter, false,                                 \
           "Prints the generated interpreter code")                          \
                                                                             \
   product(bool, UseInterpreter, true,                                       \
@@ -2300,7 +2320,7 @@
   develop(bool, PrintBytecodePairHistogram, false,                          \
           "Print histogram of the executed bytecode pairs")                 \
                                                                             \
-  develop(bool, PrintSignatureHandlers, false,                              \
+  diagnostic(bool, PrintSignatureHandlers, false,                           \
           "Print code generated for native method signature handlers")      \
                                                                             \
   develop(bool, VerifyOops, false,                                          \
--- a/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp	Fri Apr 11 09:56:35 2008 -0400
@@ -69,7 +69,6 @@
   _first_stub = _last_stub = NULL;
 }
 
-#ifndef PRODUCT
 extern "C" {
   static int compare_cdesc(const void* void_a, const void* void_b) {
     int ai = (*((StubCodeDesc**) void_a))->index();
@@ -77,10 +76,8 @@
     return ai - bi;
   }
 }
-#endif
 
 StubCodeGenerator::~StubCodeGenerator() {
-#ifndef PRODUCT
   if (PrintStubCode) {
     CodeBuffer* cbuf = _masm->code();
     CodeBlob*   blob = CodeCache::find_blob_unsafe(cbuf->insts()->start());
@@ -105,7 +102,6 @@
       tty->cr();
     }
   }
-#endif //PRODUCT
 }
 
 
--- a/hotspot/src/share/vm/runtime/vframe.hpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/runtime/vframe.hpp	Fri Apr 11 09:56:35 2008 -0400
@@ -416,6 +416,48 @@
       int decode_offset;
       if (pc_desc == NULL) {
         // Should not happen, but let fill_from_compiled_frame handle it.
+
+        // If we are trying to walk the stack of a thread that is not
+        // at a safepoint (like AsyncGetCallTrace would do) then this is an
+        // acceptable result. [ This is assuming that safe_for_sender
+        // is so bullet proof that we can trust the frames it produced. ]
+        //
+        // So if we see that the thread is not safepoint safe
+        // then simply produce the method and a bci of zero
+        // and skip the possibility of decoding any inlining that
+        // may be present. That is far better than simply stopping (or
+        // asserting. If however the thread is safepoint safe this
+        // is the sign of a compiler bug  and we'll let
+        // fill_from_compiled_frame handle it.
+
+
+        JavaThreadState state = _thread->thread_state();
+
+        // in_Java should be good enough to test safepoint safety
+        // if state were say in_Java_trans then we'd expect that
+        // the pc would have already been slightly adjusted to
+        // one that would produce a pcDesc since the trans state
+        // would be one that might in fact anticipate a safepoint
+
+        if (state == _thread_in_Java ) {
+          // This will get a method a zero bci and no inlining.
+          // Might be nice to have a unique bci to signify this
+          // particular case but for now zero will do.
+
+          fill_from_compiled_native_frame();
+
+          // There is something to be said for setting the mode to
+          // at_end_mode to prevent trying to walk further up the
+          // stack. There is evidence that if we walk any further
+          // that we could produce a bad stack chain. However until
+          // we see evidence that allowing this causes us to find
+          // frames bad enough to cause segv's or assertion failures
+          // we don't do it as while we may get a bad call chain the
+          // probability is much higher (several magnitudes) that we
+          // get good data.
+
+          return true;
+        }
         decode_offset = DebugInformationRecorder::serialized_null;
       } else {
         decode_offset = pc_desc->scope_decode_offset();
--- a/hotspot/src/share/vm/utilities/ostream.cpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/utilities/ostream.cpp	Fri Apr 11 09:56:35 2008 -0400
@@ -52,8 +52,9 @@
       _precount += _position + 1;
       _position = 0;
     } else if (ch == '\t') {
-      _position += 8;
-      _precount -= 7;  // invariant:  _precount + _position == total count
+      int tw = 8 - (_position & 7);
+      _position += tw;
+      _precount -= tw-1;  // invariant:  _precount + _position == total count
     } else {
       _position += 1;
     }
@@ -133,7 +134,17 @@
 }
 
 void outputStream::fill_to(int col) {
-  while (position() < col) sp();
+  int need_fill = col - position();
+  sp(need_fill);
+}
+
+void outputStream::move_to(int col, int slop, int min_space) {
+  if (position() >= col + slop)
+    cr();
+  int need_fill = col - position();
+  if (need_fill < min_space)
+    need_fill = min_space;
+  sp(need_fill);
 }
 
 void outputStream::put(char ch) {
@@ -142,8 +153,23 @@
   write(buf, 1);
 }
 
-void outputStream::sp() {
-  this->write(" ", 1);
+#define SP_USE_TABS false
+
+void outputStream::sp(int count) {
+  if (count < 0)  return;
+  if (SP_USE_TABS && count >= 8) {
+    int target = position() + count;
+    while (count >= 8) {
+      this->write("\t", 1);
+      count -= 8;
+    }
+    count = target - position();
+  }
+  while (count > 0) {
+    int nw = (count > 8) ? 8 : count;
+    this->write("        ", nw);
+    count -= nw;
+  }
 }
 
 void outputStream::cr() {
--- a/hotspot/src/share/vm/utilities/ostream.hpp	Thu Apr 10 15:49:16 2008 -0400
+++ b/hotspot/src/share/vm/utilities/ostream.hpp	Fri Apr 11 09:56:35 2008 -0400
@@ -59,6 +59,7 @@
    int  indentation() const    { return _indentation; }
    void set_indentation(int i) { _indentation = i;    }
    void fill_to(int col);
+   void move_to(int col, int slop = 6, int min_space = 2);
 
    // sizing
    int width()    const { return _width;    }
@@ -78,7 +79,7 @@
    void print_raw_cr(const char* str)         { write(str, strlen(str)); cr(); }
    void print_raw_cr(const char* str, int len){ write(str,         len); cr(); }
    void put(char ch);
-   void sp();
+   void sp(int count = 1);
    void cr();
    void bol() { if (_position > 0)  cr(); }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6646020/Tester.java	Fri Apr 11 09:56:35 2008 -0400
@@ -0,0 +1,886 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6646020
+ * @summary assert(in_bb(n),"must be in block") in -Xcomp mode
+ */
+
+/* Complexity upper bound: 3361 ops */
+
+class Tester_Class_0 {
+    static byte var_1;
+
+
+    public Tester_Class_0()
+    {
+        "".length();
+        {
+            var_1 = (var_1 = (new byte[(byte)'D'])[(byte)2.40457E38F]);
+            var_1 = (var_1 = (byte)1.738443503665377E307);
+            var_1 = (var_1 = (byte)1237144669662298112L);
+        }
+        var_1 = "baldh".equalsIgnoreCase("") ? (var_1 = (byte)7.2932087E37F) : (byte)3909726578709910528L;
+        var_1 = (var_1 = (var_1 = (var_1 = (byte)7.223761846153971E307)));
+        var_1 = (var_1 = (var_1 = (var_1 = (var_1 = (byte)((short)7860452029249754112L + (byte)1.7374232546809952E308)))));
+        var_1 = (!true ? (var_1 = (byte)4359229782598970368L) : (short)(byte)1.7509836746850026E308) >= 'P' ? (var_1 = (byte)3.275114793095594E307) : (byte)(- ((byte)1.5595572E38F) / 8.2971296E37F);
+        byte var_9 = (true ? true : (false ? true : false)) ? (var_1 = (var_1 = (byte)9.928434E37F)) : (var_1 = (byte)9.785060633966518E307);
+        final byte var_10 = 53;
+        var_9 <<= (true | true) & (((var_10 == "".substring(2001075014).compareToIgnoreCase("rhbytggv") ? !true : ! !true) ? !false : false) ? !true & true : !false) ? var_10 : var_10;
+        var_9 <<= - (var_9 -= - ~6397182310329038848L >> (char)955837891 << (short)- - -8.4452034E37F >> + ~5485157895941338112L);
+        --var_9;
+        var_9 >>= 'V';
+        var_9 -= (new char[var_10])[var_9];
+        double var_11;
+        var_11 = (var_11 = (new int[var_9 = (var_9 %= 684423748)])[var_9]);
+        var_9 /= 'q';
+        var_9 *= ~var_9 | (short)1.7667766368850557E308 - "w".trim().charAt(- (var_9 /= + (var_11 = 'q')));
+        if (var_10 <= 605036859609030656L | !false & false)
+        {
+            var_9 >>>= false ^ false ? (new short[var_10])[var_10] : (short)1013619326108001280L;
+        }
+        else
+        {
+            var_11 = var_9;
+        }
+        var_9 -= 'X';
+        var_9 *= 'E';
+        {
+            var_9 ^= (new short[var_9])[var_9 >>>= 'c'];
+        }
+        var_11 = 4315867074042433536L;
+        double var_12 = 1.2183900219527627E308;
+        var_9 <<= (false ? !false : false) ? '\\' : 'D';
+    }
+
+
+
+
+    private final long func_0()
+    {
+        float var_2 = 0F;
+        var_1 = (var_1 = (var_1 = (byte)((short)1.4106931056021857E308 % var_2)));
+        for (new String(); true & (! !true ^ !false | false) && var_2 < 1; var_1 = (var_1 = (var_1 = (var_1 = (byte)1183673628639185920L))))
+        {
+            var_1 = true | false ? (var_1 = (byte)1.6263855E37F) : (byte)'O';
+            var_2++;
+            "fui".toUpperCase();
+            final int var_3 = (var_1 = (var_1 = (byte)'i')) + (byte)2008561384 / (byte)1.4413369179905006E308;
+        }
+        var_1 = (var_1 = false ^ false ? (byte)2.3850814E38F : (byte)4.42887E37F);
+        final float var_4 = 3.052265E38F;
+        var_1 = (var_1 = (var_1 = (var_1 = (var_1 = (byte)'o'))));
+        long var_5;
+        var_1 = (var_1 = (byte)((var_1 = (byte)1913212786) * (var_1 = (byte)var_2)));
+        var_5 = (short)3.2024069E38F * (short)(var_5 = 'Q');
+        var_5 = (false ? true : false) ? (short)1098137179 : (byte)~695765814858203136L;
+        var_1 = (var_1 = true & false ^ true ? (byte)1662737306 : (byte)'r');
+        {
+            (true ? "a" : "lymivj".toString()).codePointCount((short)3.032349E38F + (var_1 = (var_1 = (var_1 = (var_1 = (byte)1.3159799E37F)))), (byte)2.0898819853138264E307 & (new short[(byte)(short)var_2])[var_1 = (byte)(short)4.859332921376913E307]);
+        }
+        double var_6;
+        var_6 = 1359078277;
+        final float var_7 = 3.5952457E37F;
+        var_5 = ('u' | 9005660398910009344L) << 'j';
+        int var_8;
+        var_5 = (!false || true & !false) && false ? (byte)1836342254 : (byte)1.4836203E38F;
+        var_1 = (var_1 = (var_1 = (var_1 = (byte)1.5824984701060493E308)));
+        var_1 = (var_1 = (var_1 = (byte)~ (var_1 = (var_1 = (var_1 = (byte)var_7)))));
+        return +9.067416E37F <= (true | true ^ false ? (var_1 = (byte)(short)1.5243446E38F) : (var_1 = (byte)1.6893049E37F)) ? (byte)~4408841475280588800L - (var_5 = (var_1 = (byte)2.1542209E38F)) : (var_8 = (short)var_4);
+    }
+
+    protected final static double func_1(final char arg_0, final long arg_1)
+    {
+        var_1 = (short)8779631802405542912L << 'x' <= arg_0 ? (byte)+9.96859509852443E307 : (var_1 = (var_1 = (byte)(short)5.218454879223281E307));
+        return 5.57437404144192E307;
+    }
+
+    double func_2(byte arg_0, final boolean arg_1, Object arg_2)
+    {
+        arg_2 = arg_1 != arg_1 ? "wq" : "w";
+        arg_2 = arg_2;
+        if (arg_1)
+        {
+            arg_2 = false & arg_1 ? "hasmp" : (arg_2 = arg_2);
+        }
+        else
+        {
+            arg_2 = "lcquv";
+        }
+        arg_0 -= arg_1 ^ false ? (arg_0 |= (short)arg_0) : (~3462197988186869760L | 7274210797196514304L) % - - + +130998764279904256L;
+        arg_0 &= (true ? - - ~7861994999369861120L << 'l' : 'c') * 1246069704;
+        return (arg_1 ? 9.311174E37F : 1.7085558737202237E308) * 1168887722;
+    }
+
+    public String toString()
+    {
+        String result =  "[\n";
+        result += "Tester_Class_0.var_1 = "; result += Tester.Printer.print(var_1);
+        result += "";
+        result += "\n]";
+        return result;
+    }
+}
+
+
+final class Tester_Class_1 extends Tester_Class_0 {
+    static Object var_13;
+    final static boolean var_14 = false | (false ? false : true);
+    Object var_15;
+    static byte var_16;
+    final long var_17 = (long)(-9.40561658911133E307 - (short)2.2016736E38F) ^ (char)1099667310;
+    static boolean var_18;
+    static float var_19;
+    final static byte var_20 = 123;
+    static byte var_21 = var_1 = (var_1 = var_20);
+    final static float var_22 = 1.5415572E38F;
+
+
+    public Tester_Class_1()
+    {
+        char[][] var_39;
+        boolean var_40 = false | !var_14;
+        if (var_14)
+        {
+            final String[] var_41 = (new String[var_21][var_20])[var_21 *= var_21];
+            var_15 = (new Tester_Class_0[var_20])[var_20];
+            --var_21;
+            int var_42;
+        }
+        else
+        {
+            var_19 = (short)325110146;
+        }
+        var_40 &= true;
+        var_13 = (((new Tester_Class_1[var_21 |= (new char[var_20])[var_21]])[var_21]).var_15 = (new String[var_21][var_20][var_20])[var_21 >>= (byte)(int)var_22]);
+        var_15 = "m";
+    }
+
+
+
+
+
+    protected final static Tester_Class_0 func_0(final char arg_0, boolean arg_1)
+    {
+        final short var_23 = false ? (short)2.2956268E38F : var_20;
+        {
+            ((new Tester_Class_1[var_21])[var_20]).var_15 = ((new Tester_Class_0[var_20][var_21])[var_21])[var_20];
+        }
+        var_19 = var_23;
+        {
+            var_21++;
+            --var_21;
+            var_13 = (false ? arg_1 : arg_1) ? "" : "aianteahl";
+            arg_1 ^= ! (var_14 ? var_14 : !var_14);
+        }
+        (arg_1 ? "rq" : "certd").trim();
+        arg_1 ^= 's' < var_22;
+        var_19 = 'T';
+        var_19 = var_14 ? --var_21 : var_20;
+        var_19 = (var_21 >>>= ~ -1559436447128426496L >> 88912720393932800L) | (new char[var_20][var_21])[var_21][var_20];
+        short var_24 = 7601;
+        if (arg_1)
+        {
+            var_13 = (new Tester_Class_0[var_20])[var_21];
+        }
+        else
+        {
+            var_19 = var_23;
+        }
+        var_19 = var_24;
+        var_19 = 174274929356416000L;
+        return arg_1 ? (Tester_Class_0)(new Object[var_20])[var_21 >>>= - ((byte)6471979169965446144L)] : (new Tester_Class_0[var_21])[var_20];
+    }
+
+    private static int func_1(final Object arg_0, final boolean arg_1)
+    {
+        var_19 = 'N';
+        var_13 = "ftspm".toUpperCase();
+        var_18 = arg_1 ? !arg_1 : var_14;
+        var_19 = var_21 % 'j';
+        {
+            var_13 = new short[var_21 >>= 8019540572802872320L];
+        }
+        final Tester_Class_0 var_25 = arg_1 ? ((short)1.3614569631193786E308 >= (short)var_20 ? func_0('O', true) : (Tester_Class_0)arg_0) : func_0('e', false);
+        "cltpxrg".offsetByCodePoints((new short[var_20])[(byte)'F'] & var_20, 942627356);
+        final Object var_26 = ((new Tester_Class_1[var_21])[var_20]).var_15 = arg_0;
+        {
+            var_21 |= 'H';
+        }
+        var_19 = 4705089801895780352L;
+        var_19 = (var_18 = arg_1 & false) ? var_20 : (! (~var_21 > var_22) ? (new short[var_20])[var_21] : (short)3904907750551380992L);
+        var_18 = false;
+        {
+            var_18 = "aoy".startsWith("ia", 18060804);
+            if (true)
+            {
+                final short var_27 = 4832;
+            }
+            else
+            {
+                var_18 = (var_18 = arg_1) ? !false : !var_14;
+            }
+            var_18 = (var_18 = var_14);
+            var_19 = 'L';
+        }
+        func_0((false ? ! ((var_21 -= 4.670301365216022E307) > 1.1839209E37F) : (var_18 = false)) ? 's' : 'R', 'Z' > - ((long)var_21) << 2585724390819764224L & var_25.func_2(var_21, false, var_13 = var_25) != 4918861136400833536L);
+        double var_28 = 0;
+        var_21 %= -var_28;
+        for (byte var_29 = 91; arg_1 && (var_28 < 1 && false); var_19 = var_20)
+        {
+            var_19 = (var_18 = arg_1) & (var_18 = false) ? 'm' : '[';
+            var_28++;
+            var_18 = var_14;
+            var_21 += (short)1363703973;
+        }
+        var_19 = (var_19 = var_22);
+        var_18 = (var_18 = false | false ? 1743087391 <= (var_21 >>= 8790741242417599488L) : !arg_1);
+        var_18 = true | true;
+        --var_21;
+        var_18 = !var_14 & false;
+        "mt".indexOf(var_14 ? new String("fpu") : "awivb", (var_14 ? !true : (var_18 = var_14)) ? + ++var_21 : ~var_20);
+        return (short)(new float[var_21--])[var_21] & ((var_18 = false) ? (var_21 *= 'N') : var_20 + (short)1680927063794178048L) & 1839004800;
+    }
+
+    protected static int func_2(Tester_Class_0[][] arg_0)
+    {
+        ((new Tester_Class_1[var_20][var_21])[var_20][var_20]).var_15 = ((new int[var_21][var_21][(byte)var_22])[var_21 <<= var_20])[var_20];
+        ((new Tester_Class_1[var_20])[var_20]).var_15 = "d";
+        int var_30 = 0;
+        "joxjgpywp".lastIndexOf(1834367264 >> var_21, (byte)7.572305E37F >>> (false ? (short)2.3909862E38F : + - +3939434849912855552L));
+        while (var_14 | false ^ var_14 && (var_30 < 1 && true))
+        {
+            var_1 = var_20;
+            var_30++;
+            var_13 = new float[var_21][--var_21];
+            boolean var_31;
+        }
+        var_19 = ((new Tester_Class_1[var_21])[var_20]).var_17 <= (~2158227803735181312L & 6001748808824762368L) ? (short)var_20 : var_20;
+        var_18 = (var_18 = true);
+        return (byte)(new short[var_20])[var_20] >>> ((new char[var_21][var_21])[var_21 |= 6074708801143703552L])[var_20];
+    }
+
+    private final String func_3(boolean arg_0, short arg_1, short arg_2)
+    {
+        var_13 = (Tester_Class_0)((arg_0 ^= arg_0) ? (var_13 = (var_15 = (var_15 = "grfphyrs"))) : (var_13 = new Object[var_21 *= ']']));
+        if (true & ! (arg_0 ^= !arg_0 | true))
+        {
+            boolean var_32 = true;
+            var_19 = --arg_1;
+            arg_2 <<= var_21;
+        }
+        else
+        {
+            arg_0 |= false;
+        }
+        var_21 >>>= arg_1;
+        final float var_33 = 2.5500976E38F;
+        return "";
+    }
+
+    private static String func_4(final double arg_0, final Object arg_1, final short[] arg_2, final char arg_3)
+    {
+        float var_34;
+        var_21++;
+        ((new Tester_Class_1[var_20])[var_20]).var_15 = false ? arg_1 : arg_1;
+        var_13 = arg_1;
+        var_19 = var_22;
+        var_13 = new long[var_21 /= 1038797776 + var_21][--var_21];
+        ++var_21;
+        var_18 = false && false;
+        var_21--;
+        "".lastIndexOf("kjro");
+        final int var_35 = (var_21 <<= var_21--) * var_21--;
+        if ("kohilkx".startsWith("gy", var_35))
+        {
+            var_34 = 2.0849673E37F;
+        }
+        else
+        {
+            double var_36 = arg_0;
+        }
+        var_34 = (var_21 /= var_20);
+        {
+            func_2(new Tester_Class_0[var_20][var_21]);
+            var_34 = var_20 * (- ~5805881602002385920L / arg_3) << (short)~8041668398152312832L;
+            var_13 = (var_13 = "qfwbfdf");
+        }
+        ((new Tester_Class_1[var_20])[var_21 += var_20]).var_15 = false ? func_0(arg_3, var_14) : func_0('J', var_18 = var_14);
+        var_18 = (var_18 = var_14) & var_14;
+        if ((new boolean[var_21])[var_21 >>= 121380821])
+        {
+            var_34 = 1382979413;
+        }
+        else
+        {
+            var_34 = (var_20 & var_20) + (true ? 'I' : arg_3);
+        }
+        byte var_37;
+        ((new Tester_Class_1[var_20][var_21])[var_14 ^ var_14 | !var_14 ? var_20 : var_20][var_21 ^= (short)1692053070 & + ~7232298887878750208L - 1512699919]).var_15 = arg_2;
+        byte var_38 = 1;
+        var_38 -= arg_0;
+        var_34 = arg_3;
+        return var_14 ? "" : "xgkr".toUpperCase();
+    }
+
+    public String toString()
+    {
+        String result =  "[\n";
+        result += "Tester_Class_1.var_1 = "; result += Tester.Printer.print(var_1);
+        result += "\n";
+        result += "Tester_Class_1.var_16 = "; result += Tester.Printer.print(var_16);
+        result += "\n";
+        result += "Tester_Class_1.var_20 = "; result += Tester.Printer.print(var_20);
+        result += "\n";
+        result += "Tester_Class_1.var_21 = "; result += Tester.Printer.print(var_21);
+        result += "\n";
+        result += "Tester_Class_1.var_14 = "; result += Tester.Printer.print(var_14);
+        result += "\n";
+        result += "Tester_Class_1.var_18 = "; result += Tester.Printer.print(var_18);
+        result += "\n";
+        result += "Tester_Class_1.var_17 = "; result += Tester.Printer.print(var_17);
+        result += "\n";
+        result += "Tester_Class_1.var_19 = "; result += Tester.Printer.print(var_19);
+        result += "\n";
+        result += "Tester_Class_1.var_22 = "; result += Tester.Printer.print(var_22);
+        result += "\n";
+        result += "Tester_Class_1.var_13 = "; result += Tester.Printer.print(var_13);
+        result += "\n";
+        result += "Tester_Class_1.var_15 = "; result += Tester.Printer.print(var_15);
+        result += "";
+        result += "\n]";
+        return result;
+    }
+}
+
+
+class Tester_Class_2 extends Tester_Class_0 {
+    final int var_43 = 1600723343;
+    static long var_44 = ~1297640037857117184L;
+    static String var_45 = "ejaglds";
+    double var_46;
+    static float var_47 = 7.9423827E37F;
+    static Tester_Class_1[][] var_48;
+
+
+    public Tester_Class_2()
+    {
+        var_45 = (var_45 = "nkulkweqt");
+        var_47 %= (new char[Tester_Class_1.var_21 >>= (short)Tester_Class_1.var_20])[Tester_Class_1.var_20];
+        {
+            Tester_Class_1.var_18 = Tester_Class_1.var_14;
+        }
+        var_47 %= 1.559461406041646E308;
+        var_44 -= Tester_Class_1.var_21++ & ((new Tester_Class_1[Tester_Class_1.var_20])[Tester_Class_1.var_20]).var_17;
+        var_44 *= false ? (short)Tester_Class_1.var_20 : (short)var_47;
+        Tester_Class_1.var_13 = (new Tester_Class_1().var_15 = new char[Tester_Class_1.var_20]);
+        var_46 = 'i';
+        double var_49 = var_46 = false ? (var_47 *= (var_46 = var_43)) : Tester_Class_1.var_20;
+        var_49 += 'k';
+    }
+
+
+
+
+    public String toString()
+    {
+        String result =  "[\n";
+        result += "Tester_Class_2.var_43 = "; result += Tester.Printer.print(var_43);
+        result += "\n";
+        result += "Tester_Class_2.var_48 = "; result += Tester.Printer.print(var_48);
+        result += "\n";
+        result += "Tester_Class_2.var_44 = "; result += Tester.Printer.print(var_44);
+        result += "\n";
+        result += "Tester_Class_2.var_46 = "; result += Tester.Printer.print(var_46);
+        result += "\n";
+        result += "Tester_Class_2.var_47 = "; result += Tester.Printer.print(var_47);
+        result += "\n";
+        result += "Tester_Class_2.var_1 = "; result += Tester.Printer.print(var_1);
+        result += "\n";
+        result += "Tester_Class_2.var_45 = "; result += Tester.Printer.print(var_45);
+        result += "";
+        result += "\n]";
+        return result;
+    }
+}
+
+
+class Tester_Class_3 extends Tester_Class_0 {
+    byte var_50;
+    int var_51;
+    static double var_52;
+    static boolean var_53 = true;
+    long var_54;
+    static short var_55;
+    short var_56;
+
+
+    public Tester_Class_3()
+    {
+        var_53 |= false;
+        (Tester_Class_2.var_45 = "gpbcgq").replaceAll("m".concat(Tester_Class_2.var_45 = "q"), Tester_Class_2.var_45).indexOf(Tester_Class_2.var_45 = "d");
+        Tester_Class_2.var_45 = Tester_Class_2.var_45;
+        double var_68 = 0;
+        Tester_Class_1.var_19 = (var_55 = Tester_Class_1.var_20);
+        do
+        {
+            var_53 ^= 'T' > Tester_Class_1.var_21-- & (var_53 |= Tester_Class_1.var_14);
+            Tester_Class_2.var_44 >>= (char)3.928497616986412E307;
+            var_68++;
+            new Tester_Class_2().func_2(Tester_Class_1.var_20, !var_53 & Tester_Class_1.var_14, Tester_Class_1.var_13 = (Tester_Class_2.var_45 = Tester_Class_2.var_45));
+        } while ((((var_56 = (short)1161292485) != 'M' ? var_53 : Tester_Class_1.var_14) ? Tester_Class_1.var_14 ^ true : var_53) && var_68 < 1);
+        Tester_Class_2.var_45 = Tester_Class_2.var_45;
+        ((Tester_Class_1)(Tester_Class_1.var_13 = new Tester_Class_2())).var_15 = Tester_Class_2.var_45;
+        var_55 = func_1() | ((Tester_Class_1.var_18 = var_53) | (var_53 |= Tester_Class_1.var_14) | Tester_Class_1.var_14 | !Tester_Class_1.var_14) || false ? (short)Tester_Class_2.var_44 : (var_56 = (var_56 = (short)'['));
+        var_52 = (var_51 = (var_55 = Tester_Class_1.var_20));
+        double var_69 = 0;
+        Tester_Class_2.var_44 |= (Tester_Class_1.var_14 ? (Tester_Class_2)(Tester_Class_1.var_13 = (Tester_Class_2)(Tester_Class_1.var_13 = Tester_Class_2.var_45)) : (Tester_Class_2)(Tester_Class_0)(Tester_Class_1.var_13 = Tester_Class_2.var_45)).var_43;
+        do
+        {
+            var_51 = 495861255;
+            var_69++;
+        } while (var_69 < 3);
+        Tester_Class_2.var_47 -= Tester_Class_1.var_20;
+        Tester_Class_2.var_47 %= '[';
+    }
+
+
+
+
+    static Object func_0(final Tester_Class_0 arg_0, String arg_1, final float arg_2, final long arg_3)
+    {
+        (!var_53 | (var_53 &= var_53) ^ false ? new Tester_Class_1() : (Tester_Class_1)(new Tester_Class_0[Tester_Class_1.var_21])[Tester_Class_1.var_21]).var_15 = Tester_Class_1.var_14 ? new Tester_Class_1() : new Tester_Class_1();
+        Tester_Class_2.var_47 /= !var_53 || var_53 ? (short)(((Tester_Class_2)arg_0).var_46 = (new char[Tester_Class_1.var_21][Tester_Class_1.var_21])[Tester_Class_1.var_20][Tester_Class_1.var_20]) : Tester_Class_1.var_21;
+        return (new Object[Tester_Class_1.var_21])[Tester_Class_1.var_21];
+    }
+
+    boolean func_1()
+    {
+        {
+            Tester_Class_1.var_21 >>= (var_56 = (Tester_Class_1.var_21 |= (Tester_Class_1.var_21 -= Tester_Class_1.var_20)));
+            Tester_Class_2.var_45 = "w";
+            var_51 = Tester_Class_1.var_21;
+            Object var_57;
+            ((Tester_Class_2)(Tester_Class_0)((new Object[Tester_Class_1.var_21][Tester_Class_1.var_21])[Tester_Class_1.var_20])[Tester_Class_1.var_20]).var_46 = (var_52 = 1.3957085765622284E308);
+        }
+        Tester_Class_1.var_21 &= (var_55 = (byte)(Tester_Class_1.var_14 ? -Tester_Class_1.var_20 : 4290961666344782848L));
+        Tester_Class_2.var_45 = Tester_Class_2.var_45;
+        var_51 = (var_53 ^= ((var_53 &= Tester_Class_1.var_14) ? 'J' : 'M') > (var_56 = Tester_Class_1.var_21)) && (var_53 = Tester_Class_1.var_14) ? (Tester_Class_1.var_21 &= ~Tester_Class_1.var_20) : Tester_Class_1.var_20;
+        {
+            final Tester_Class_1 var_58 = (Tester_Class_1)(Tester_Class_0)(Tester_Class_1.var_13 = (new Object[Tester_Class_1.var_21])[Tester_Class_1.var_20]);
+            Object var_59;
+            Tester_Class_1.var_21 |= 'X';
+            var_53 ^= Tester_Class_1.var_14;
+        }
+        int var_60 = 0;
+        var_53 |= var_53;
+        for (char var_61 = 'i'; (Tester_Class_1.var_14 ? false : Tester_Class_1.var_14) | (true | Tester_Class_1.var_14) && var_60 < 1; var_53 &= !Tester_Class_1.var_14)
+        {
+            var_51 = var_61;
+            var_60++;
+            var_61 &= (new short[Tester_Class_1.var_20][Tester_Class_1.var_20])[Tester_Class_1.var_20][Tester_Class_1.var_21];
+            Tester_Class_2.var_45 = "vsuy";
+        }
+        Tester_Class_2 var_62 = ((var_53 &= Tester_Class_1.var_14 | Tester_Class_1.var_14 || Tester_Class_1.var_14) ? Tester_Class_1.var_14 : "hgwne".startsWith("etyhd", var_60)) ? (var_53 ? (Tester_Class_2)(Tester_Class_1.var_13 = "uyiaxtqc") : (Tester_Class_2)(Tester_Class_1.var_13 = Tester_Class_2.var_45)) : new Tester_Class_2();
+        var_62 = var_62;
+        float var_63;
+        Object var_64;
+        Tester_Class_2.var_44 <<= 'v';
+        String var_65;
+        {
+            var_51 = Tester_Class_1.var_21;
+        }
+        var_55 = true ? (var_56 = Tester_Class_1.var_20) : (var_55 = Tester_Class_1.var_20);
+        var_56 = Tester_Class_1.var_21;
+        Tester_Class_1.var_21 |= var_60;
+        Object var_66;
+        Tester_Class_2 var_67;
+        return true & Tester_Class_1.var_14 ^ (false ? var_53 : var_53);
+    }
+
+    public String toString()
+    {
+        String result =  "[\n";
+        result += "Tester_Class_3.var_51 = "; result += Tester.Printer.print(var_51);
+        result += "\n";
+        result += "Tester_Class_3.var_54 = "; result += Tester.Printer.print(var_54);
+        result += "\n";
+        result += "Tester_Class_3.var_52 = "; result += Tester.Printer.print(var_52);
+        result += "\n";
+        result += "Tester_Class_3.var_55 = "; result += Tester.Printer.print(var_55);
+        result += "\n";
+        result += "Tester_Class_3.var_56 = "; result += Tester.Printer.print(var_56);
+        result += "\n";
+        result += "Tester_Class_3.var_1 = "; result += Tester.Printer.print(var_1);
+        result += "\n";
+        result += "Tester_Class_3.var_50 = "; result += Tester.Printer.print(var_50);
+        result += "\n";
+        result += "Tester_Class_3.var_53 = "; result += Tester.Printer.print(var_53);
+        result += "";
+        result += "\n]";
+        return result;
+    }
+}
+
+public class Tester {
+    final long var_70 = Tester_Class_2.var_44;
+    int var_71;
+    static double var_72;
+    static short var_73 = (Tester_Class_3.var_53 &= (Tester_Class_3.var_53 ^= Tester_Class_3.var_53)) ? (short)(byte)(Tester_Class_3.var_55 = Tester_Class_1.var_20) : (Tester_Class_3.var_55 = Tester_Class_1.var_20);
+    final static short var_74 = (Tester_Class_3.var_53 &= Tester_Class_3.var_53) ? (Tester_Class_3.var_53 ? var_73 : var_73++) : (var_73 *= (Tester_Class_1.var_21 |= var_73));
+    float var_75;
+
+
+    protected final Tester_Class_2 func_0()
+    {
+        Tester_Class_1.var_21 ^= ~Tester_Class_1.var_21;
+        if (false)
+        {
+            ((Tester_Class_3)(new Object[Tester_Class_1.var_21])[Tester_Class_1.var_21 -= + + (Tester_Class_2.var_44 >>>= Tester_Class_1.var_21)]).var_50 = (Tester_Class_1.var_21 &= (var_71 = 554295231));
+        }
+        else
+        {
+            Tester_Class_2.var_47 += 'H';
+        }
+        final Tester_Class_0 var_76 = ((new Tester_Class_0[Tester_Class_1.var_20][Tester_Class_1.var_21])[Tester_Class_1.var_20])[Tester_Class_1.var_20];
+        (Tester_Class_1.var_14 ? (Tester_Class_2)var_76 : (Tester_Class_2)var_76).var_46 = (var_73 %= var_74 / (((new Tester_Class_2[Tester_Class_1.var_20])[Tester_Class_1.var_21 |= Tester_Class_1.var_20]).var_46 = Tester_Class_1.var_22));
+        var_73 |= ((Tester_Class_2)(Tester_Class_1.var_13 = var_76)).var_43 | Tester_Class_1.var_20;
+        return new Tester_Class_2();
+    }
+
+    private static Tester_Class_3 func_1(byte arg_0, Tester_Class_1 arg_1, Tester_Class_1 arg_2, final int arg_3)
+    {
+        arg_0 <<= '`';
+        return false ? (Tester_Class_3)(Tester_Class_0)(arg_1.var_15 = (arg_1 = arg_2)) : (Tester_Class_3)((new Tester_Class_0[Tester_Class_1.var_20][arg_0])[Tester_Class_1.var_20])[Tester_Class_1.var_20];
+    }
+
+    public static String execute()
+    {
+        try {
+            Tester t = new Tester();
+            try { t.test(); }
+            catch(Throwable e) { }
+            try { return t.toString(); }
+            catch (Throwable e) { return "Error during result conversion to String"; }
+        } catch (Throwable e) { return "Error during test execution"; }
+    }
+
+    public static void main(String[] args)
+    {
+        for (int i = 0; i < 20000; i++) {
+            Tester t = new Tester();
+            try { t.test(); }
+            catch(Throwable e) { }
+            if (t.var_71 != 0 ||
+                t.var_70 != -1297640037857117185L ||
+                t.var_72 != 0.0 ||
+                t.var_75 != 0.0 ||
+                t.var_73 != -1 ||
+                t.var_74 != 15129) {
+                throw new InternalError("wrong answer");
+            }
+        }
+    }
+
+    private void test()
+    {
+        long var_77 = 0L;
+        var_73 /= (Tester_Class_2.var_47 = 'D' | 'Q');
+        Tester_Class_2.var_47 *= 't';
+        while (var_77 < 36)
+        {
+            var_73 += Tester_Class_1.var_22;
+            Tester_Class_2.var_47 += Tester_Class_1.var_20;
+            var_77++;
+            Tester_Class_2.var_45 = "";
+            Tester_Class_2.var_45 = (Tester_Class_2.var_45 = Tester_Class_2.var_45);
+        }
+        if (Tester_Class_3.var_53 |= false)
+        {
+            int var_78 = 0;
+            (false ? "idipdjrln" : "l").startsWith(Tester_Class_2.var_45);
+            while ((Tester_Class_3.var_53 |= (Tester_Class_3.var_53 &= ! (Tester_Class_1.var_18 = true)) | Tester_Class_3.var_53) && (var_78 < 15 && (Tester_Class_3.var_53 &= Tester_Class_1.var_14)))
+            {
+                Tester_Class_2.var_44 <<= 'b';
+                var_78++;
+                var_72 = var_74;
+                var_71 = (char)6792782617594333184L;
+            }
+            float var_79 = Tester_Class_2.var_47 /= 1.5148047552641134E308;
+            ((new boolean[Tester_Class_1.var_20])[Tester_Class_1.var_21 <= (Tester_Class_1.var_21 -= 9.675021723726166E307) / - + (var_72 = 4.3844763012510596E307) ? (byte)(Tester_Class_2.var_44 += ~Tester_Class_1.var_21) : (Tester_Class_1.var_21 += 1.7430965313164616E308)] ? (Tester_Class_2)(new Tester_Class_1().var_15 = func_0()) : new Tester_Class_2()).var_46 = (var_72 = (Tester_Class_1.var_21 *= 'j'));
+            Tester_Class_1.var_13 = (new Tester_Class_3[Tester_Class_1.var_21 >>>= var_78][Tester_Class_1.var_21])[Tester_Class_1.var_21][Tester_Class_1.var_20];
+        }
+        else
+        {
+            long var_80 = 0L;
+            ((Tester_Class_2)(Tester_Class_1.var_13 = new long[Tester_Class_1.var_21])).var_46 = 'r';
+            do
+            {
+                final float var_81 = 7.3633934E37F;
+                var_80++;
+                var_73 ^= Tester_Class_2.var_44;
+            } while (Tester_Class_3.var_53 && var_80 < 4);
+            Tester_Class_1.var_18 = Tester_Class_2.var_47 >= var_73;
+            Tester_Class_2.var_45 = "xvodcylp";
+            Tester_Class_2.var_45.codePointCount("indreb".charAt(+(new byte[Tester_Class_1.var_20][Tester_Class_1.var_20])[Tester_Class_1.var_21][Tester_Class_1.var_21]) * ~ (Tester_Class_1.var_21 %= (var_71 = --var_73)), ((Tester_Class_3.var_53 ^= Tester_Class_2.var_45.equalsIgnoreCase("rkxwa")) || Tester_Class_2.var_47 <= (Tester_Class_2.var_47 %= -var_80) ? (Tester_Class_1.var_21 ^= var_70) : var_73) & (var_71 = 'k'));
+            Tester_Class_1.var_13 = ((new long[Tester_Class_1.var_21][Tester_Class_1.var_20][Tester_Class_1.var_21])[Tester_Class_1.var_21])[Tester_Class_1.var_21];
+        }
+        var_73 <<= (Tester_Class_1.var_18 = false) ? 't' : (false ? 'E' : 'u');
+        var_73++;
+        int var_82 = 0;
+        Tester_Class_1.var_13 = func_1(Tester_Class_1.var_20, new Tester_Class_1(), (new Tester_Class_1[Tester_Class_1.var_21])[Tester_Class_1.var_21], 'M' & var_74);
+        "gdrlrsubb".substring(12438522, var_82);
+        Tester_Class_2.var_44 |= (((new Tester_Class_3[Tester_Class_1.var_21][Tester_Class_1.var_21])[Tester_Class_1.var_21 >>= 7993744087962264576L][Tester_Class_1.var_21]).var_51 = Tester_Class_3.var_53 ? 'B' : '[');
+        final long var_83 = ~ (4544638910183665664L << (((Tester_Class_3)((new Tester_Class_0[Tester_Class_1.var_20][Tester_Class_1.var_21])[Tester_Class_1.var_21])[Tester_Class_1.var_21]).var_56 = (Tester_Class_3.var_53 &= Tester_Class_3.var_53) ? Tester_Class_1.var_21 : Tester_Class_1.var_20));
+        Tester_Class_2.var_45 = Tester_Class_2.var_45;
+        while (var_82 < 2 && Tester_Class_3.var_53 & (Tester_Class_3.var_53 ^= !false))
+        {
+            (Tester_Class_3.var_53 ? "xqeisnyf" : (Tester_Class_2.var_45 = (Tester_Class_2.var_45 = (Tester_Class_2.var_45 = Tester_Class_2.var_45)))).concat(Tester_Class_2.var_45 = "i");
+            var_82++;
+            boolean var_84 = false;
+            Tester_Class_2.var_45 = Tester_Class_2.var_45;
+        }
+        var_71 = ~Tester_Class_2.var_44 != Tester_Class_2.var_44-- ? (var_73 = var_73) : (var_73 >>>= var_73);
+        char var_85;
+        Tester_Class_3.var_53 |= (Tester_Class_3.var_53 ^= true);
+        int var_86 = 0;
+        Tester_Class_1.var_21 %= (var_73 | (Tester_Class_1.var_21 *= 9.831691E37F)) * (Tester_Class_1.var_21 += 6784278051481715712L);
+        while (Tester_Class_3.var_53 && (var_86 < 24 && ((((Tester_Class_3.var_53 ^= true) ? Tester_Class_3.var_53 : Tester_Class_1.var_14) ? !Tester_Class_3.var_53 : Tester_Class_3.var_53) ? (Tester_Class_1.var_18 = Tester_Class_3.var_53) : Tester_Class_1.var_14 || true)))
+        {
+            final byte var_87 = (byte)((false & true ? Tester_Class_1.var_20 : 257407175) & 4242055901066916864L * (var_73 *= 1621204618) / ((((Tester_Class_1)(new Object[(byte)4.925362697409246E307])[Tester_Class_1.var_21]).var_17 ^ (var_71 = var_86)) & 1859382584));
+            var_86++;
+            Tester_Class_2.var_45 = (Tester_Class_2.var_45 = (Tester_Class_2.var_45 = "arceo"));
+            float var_88;
+        }
+        "a".lastIndexOf(var_71 = Tester_Class_3.var_53 ^ false ? (var_71 = 1058420888) : Tester_Class_1.var_20);
+        int var_89 = 0;
+        {
+            var_71 = 661164411;
+        }
+        boolean var_90;
+        --var_73;
+        Tester_Class_2.var_45.concat(Tester_Class_2.var_45);
+        {
+            var_85 = (Tester_Class_3.var_53 ? Tester_Class_3.var_53 : Tester_Class_3.var_53) ? 'R' : '[';
+        }
+        ((new Tester_Class_2[Tester_Class_1.var_21][Tester_Class_1.var_21])[Tester_Class_1.var_20][Tester_Class_1.var_20]).var_46 = Tester_Class_1.var_20;
+        final float var_91 = ((new Tester_Class_0[Tester_Class_1.var_21][Tester_Class_1.var_21])[Tester_Class_1.var_20][Tester_Class_1.var_21 -= Tester_Class_1.var_21]).equals(((new Tester_Class_1[Tester_Class_1.var_20])[Tester_Class_1.var_21]).var_15 = (Tester_Class_2.var_45 = Tester_Class_2.var_45)) ? (var_71 = Tester_Class_1.var_20) : 2.2259766E38F + Tester_Class_2.var_44;
+        Tester_Class_2.var_47 *= ((Tester_Class_2)(Tester_Class_0)(Tester_Class_1.var_13 = Tester_Class_2.var_45)).var_43;
+        Tester_Class_2.var_45 = Tester_Class_2.var_45;
+        Tester_Class_3.var_53 &= Tester_Class_1.var_14;
+        while (Tester_Class_1.var_20 >= ++Tester_Class_1.var_21 && var_89 < 2)
+        {
+            Tester_Class_1.var_13 = (Tester_Class_3)(new Tester_Class_0[Tester_Class_1.var_21])[Tester_Class_1.var_21];
+            var_89++;
+            if (true)
+            {
+                Tester_Class_3.var_53 |= true;
+                break;
+            }
+            else
+            {
+                Tester_Class_2 var_92;
+            }
+            ((Tester_Class_3)((Tester_Class_3.var_53 |= Tester_Class_3.var_53) ? (new Tester_Class_1().var_15 = (Tester_Class_0)(Tester_Class_1.var_13 = new boolean[Tester_Class_1.var_20][Tester_Class_1.var_21])) : new Tester_Class_0[Tester_Class_1.var_21][Tester_Class_1.var_21])).var_54 = (Tester_Class_1.var_21 = (Tester_Class_1.var_21 /= (Tester_Class_2.var_44 |= (int)(Tester_Class_1.var_21 >>>= var_82))));
+            ((Tester_Class_3)(Tester_Class_1.var_13 = (new Tester_Class_1().var_15 = new Tester_Class_1()))).var_51 = Tester_Class_1.var_20;
+            final char var_93 = 'u';
+            ((Tester_Class_2)(new Tester_Class_1().var_15 = (Tester_Class_2.var_45 = Tester_Class_2.var_45))).var_46 = var_93;
+            Tester_Class_2.var_45.toUpperCase();
+            Tester_Class_2.var_45 = "mhk";
+            (true | false ? new Tester_Class_1() : (new Tester_Class_1[Tester_Class_1.var_20])[Tester_Class_1.var_20]).var_15 = (Tester_Class_1)(((new Tester_Class_1[Tester_Class_1.var_21 |= Tester_Class_1.var_20][Tester_Class_1.var_21])[Tester_Class_1.var_21][Tester_Class_1.var_21]).var_15 = (Tester_Class_1.var_13 = (Tester_Class_1)(Tester_Class_1.var_13 = (Tester_Class_2.var_45 = "ofkbg"))));
+        }
+        float var_94 = 0F;
+        Tester_Class_2.var_44 |= (var_73 >>>= (var_85 = (var_85 = 'j')));
+        Tester_Class_3.var_52 = 1835242863964218368L;
+        do
+        {
+            int var_95 = 1361237611;
+            var_94++;
+            Tester_Class_3.var_53 ^= (Tester_Class_3.var_53 |= Tester_Class_1.var_14);
+        } while (var_94 < 16);
+        {
+            var_73 = var_73--;
+            Tester_Class_2.var_45 = (Tester_Class_1.var_14 ? Tester_Class_1.var_14 : !false) ? "oaxg" : "igdnja";
+        }
+        ((new Tester_Class_1[Tester_Class_1.var_21])[Tester_Class_1.var_21]).equals(new Tester_Class_1().var_15 = (Tester_Class_2.var_45 = "agdnue").charAt(1416972150) != Tester_Class_2.var_47 ? new Tester_Class_1() : new Tester_Class_1());
+        byte var_96 = Tester_Class_1.var_21 >>>= (var_85 = (var_85 = '`'));
+        Tester_Class_2.var_45 = "";
+        Tester_Class_2.var_47 += Tester_Class_2.var_47;
+        Tester_Class_2.var_45 = Tester_Class_2.var_45;
+    }
+    public String toString()
+    {
+        String result =  "[\n";
+        result += "Tester.var_71 = "; result += Printer.print(var_71);
+        result += "\n";
+        result += "Tester.var_70 = "; result += Printer.print(var_70);
+        result += "\n";
+        result += "Tester.var_72 = "; result += Printer.print(var_72);
+        result += "\n";
+        result += "Tester.var_75 = "; result += Printer.print(var_75);
+        result += "\n";
+        result += "Tester.var_73 = "; result += Printer.print(var_73);
+        result += "\n";
+        result += "Tester.var_74 = "; result += Printer.print(var_74);
+        result += "";
+        result += "\n]";
+        return result;
+    }
+    static class Printer
+    {
+        public static String print(boolean arg) { return String.valueOf(arg); }
+        public static String print(byte arg)    { return String.valueOf(arg); }
+        public static String print(short arg)   { return String.valueOf(arg); }
+        public static String print(char arg)    { return String.valueOf((int)arg); }
+        public static String print(int arg)     { return String.valueOf(arg); }
+        public static String print(long arg)    { return String.valueOf(arg); }
+        public static String print(float arg)   { return String.valueOf(arg); }
+        public static String print(double arg)  { return String.valueOf(arg); }
+
+
+        public static String print(Object arg)
+        {
+            return print_r(new java.util.Stack(), arg);
+        }
+
+        private static String print_r(java.util.Stack visitedObjects, Object arg)
+        {
+            String result = "";
+            if (arg == null)
+                result += "null";
+            else
+            if (arg.getClass().isArray())
+            {
+                for (int i = 0; i < visitedObjects.size(); i++)
+                    if (visitedObjects.elementAt(i) == arg) return "<recursive>";
+
+                visitedObjects.push(arg);
+
+                final String delimiter = ", ";
+                result += "[";
+
+                if (arg instanceof Object[])
+                {
+                    Object[] array = (Object[]) arg;
+                    for (int i = 0; i < array.length; i++)
+                    {
+                        result += print_r(visitedObjects, array[i]);
+                        if (i < array.length - 1) result += delimiter;
+                    }
+                }
+                else
+                if (arg instanceof boolean[])
+                {
+                    boolean[] array = (boolean[]) arg;
+                    for (int i = 0; i < array.length; i++)
+                    {
+                        result += print(array[i]);
+                        if (i < array.length - 1) result += delimiter;
+                    }
+                }
+                else
+                if (arg instanceof byte[])
+                {
+                    byte[] array = (byte[]) arg;
+                    for (int i = 0; i < array.length; i++)
+                    {
+                        result += print(array[i]);
+                        if (i < array.length - 1) result += delimiter;
+                    }
+                }
+                else
+                if (arg instanceof short[])
+                {
+                    short[] array = (short[]) arg;
+                    for (int i = 0; i < array.length; i++)
+                    {
+                        result += print(array[i]);
+                        if (i < array.length - 1) result += delimiter;
+                    }
+                }
+                else
+                if (arg instanceof char[])
+                {
+                    char[] array = (char[]) arg;
+                    for (int i = 0; i < array.length; i++)
+                    {
+                        result += print(array[i]);
+                        if (i < array.length - 1) result += delimiter;
+                    }
+                }
+                else
+                if (arg instanceof int[])
+                {
+                     int[] array = (int[]) arg;
+                     for (int i = 0; i < array.length; i++)
+                     {
+                        result += print(array[i]);
+                        if (i < array.length - 1) result += delimiter;
+                     }
+                }
+                else
+                if (arg instanceof long[])
+                {
+                    long[] array = (long[]) arg;
+                    for (int i = 0; i < array.length; i++)
+                    {
+                        result += print(array[i]);
+                        if (i < array.length - 1) result += delimiter;
+                    }
+                }
+                else
+                if (arg instanceof float[])
+                {
+                    float[] array = (float[]) arg;
+                    for (int i = 0; i < array.length; i++)
+                    {
+                        result += print(array[i]);
+                        if (i < array.length - 1) result += delimiter;
+                    }
+                }
+                else
+                if (arg instanceof double[])
+                {
+                    double[] array = (double[]) arg;
+                    for (int i = 0; i < array.length; i++)
+                    {
+                        result += print(array[i]);
+                        if (i < array.length - 1) result += delimiter;
+                    }
+                }
+
+                result += "]";
+                visitedObjects.pop();
+
+            } else
+            {
+                result += arg.toString();
+            }
+
+            return result;
+        }
+    }
+}
+
+