changeset 1700:f03d0a26bf83

6888954: argument formatting for assert() and friends Reviewed-by: kvn, twisti, apetrusenko, never, dcubed
author jcoomes
date Thu, 22 Apr 2010 13:23:15 -0700
parents cff162798819
children befdf73d6b82 3bfae429e2cf
files src/cpu/sparc/vm/assembler_sparc.hpp src/os/linux/vm/os_linux.cpp src/os/solaris/vm/os_solaris.cpp src/os/solaris/vm/threadCritical_solaris.cpp src/os/windows/vm/os_windows.cpp src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp src/os_cpu/linux_x86/vm/os_linux_x86.cpp src/share/vm/asm/assembler.cpp src/share/vm/classfile/classFileParser.cpp src/share/vm/code/exceptionHandlerTable.cpp src/share/vm/code/nmethod.cpp src/share/vm/code/stubs.cpp src/share/vm/code/vtableStubs.cpp src/share/vm/interpreter/bytecodeInterpreter.cpp src/share/vm/interpreter/bytecodes.cpp src/share/vm/oops/instanceKlass.cpp src/share/vm/oops/instanceKlassKlass.cpp src/share/vm/oops/klassVtable.cpp src/share/vm/opto/idealGraphPrinter.cpp src/share/vm/opto/output.cpp src/share/vm/prims/jni.cpp src/share/vm/runtime/globals.hpp src/share/vm/runtime/memprofiler.cpp src/share/vm/runtime/mutex.cpp src/share/vm/runtime/mutexLocker.cpp src/share/vm/runtime/os.cpp src/share/vm/runtime/safepoint.cpp src/share/vm/runtime/signature.cpp src/share/vm/runtime/stubRoutines.cpp src/share/vm/runtime/vmThread.cpp src/share/vm/utilities/debug.cpp src/share/vm/utilities/debug.hpp src/share/vm/utilities/exceptions.cpp src/share/vm/utilities/macros.hpp src/share/vm/utilities/vmError.cpp src/share/vm/utilities/vmError.hpp test/runtime/6888954/vmerrors.sh
diffstat 37 files changed, 400 insertions(+), 215 deletions(-) [+]
line wrap: on
line diff
--- a/src/cpu/sparc/vm/assembler_sparc.hpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/cpu/sparc/vm/assembler_sparc.hpp	Thu Apr 22 13:23:15 2010 -0700
@@ -1065,7 +1065,7 @@
   }
   void assert_not_delayed(const char* msg) {
 #ifdef CHECK_DELAY
-    assert_msg ( delay_state == no_delay, msg);
+    assert(delay_state == no_delay, msg);
 #endif
   }
 
--- a/src/os/linux/vm/os_linux.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/os/linux/vm/os_linux.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -3495,7 +3495,8 @@
       // libjsig also interposes the sigaction() call below and saves the
       // old sigaction on it own.
     } else {
-      fatal2("Encountered unexpected pre-existing sigaction handler %#lx for signal %d.", (long)oldhand, sig);
+      fatal(err_msg("Encountered unexpected pre-existing sigaction handler "
+                    "%#lx for signal %d.", (long)oldhand, sig));
     }
   }
 
@@ -3817,7 +3818,8 @@
 
   Linux::set_page_size(sysconf(_SC_PAGESIZE));
   if (Linux::page_size() == -1) {
-    fatal1("os_linux.cpp: os::init: sysconf failed (%s)", strerror(errno));
+    fatal(err_msg("os_linux.cpp: os::init: sysconf failed (%s)",
+                  strerror(errno)));
   }
   init_page_sizes((size_t) Linux::page_size());
 
--- a/src/os/solaris/vm/os_solaris.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/os/solaris/vm/os_solaris.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -1567,7 +1567,8 @@
   //           treat %g2 as a caller-save register, preserving it in a %lN.
   thread_key_t tk;
   if (thr_keycreate( &tk, NULL ) )
-    fatal1("os::allocate_thread_local_storage: thr_keycreate failed (%s)", strerror(errno));
+    fatal(err_msg("os::allocate_thread_local_storage: thr_keycreate failed "
+                  "(%s)", strerror(errno)));
   return int(tk);
 }
 
@@ -1585,7 +1586,8 @@
     if (errno == ENOMEM) {
        vm_exit_out_of_memory(SMALLINT, "thr_setspecific: out of swap space");
     } else {
-      fatal1("os::thread_local_storage_at_put: thr_setspecific failed (%s)", strerror(errno));
+      fatal(err_msg("os::thread_local_storage_at_put: thr_setspecific failed "
+                    "(%s)", strerror(errno)));
     }
   } else {
       ThreadLocalStorage::set_thread_in_slot ((Thread *) value) ;
@@ -1738,7 +1740,7 @@
 jlong os::javaTimeMillis() {
   timeval t;
   if (gettimeofday( &t, NULL) == -1)
-    fatal1("os::javaTimeMillis: gettimeofday (%s)", strerror(errno));
+    fatal(err_msg("os::javaTimeMillis: gettimeofday (%s)", strerror(errno)));
   return jlong(t.tv_sec) * 1000  +  jlong(t.tv_usec) / 1000;
 }
 
@@ -4233,7 +4235,8 @@
       // libjsig also interposes the sigaction() call below and saves the
       // old sigaction on it own.
     } else {
-      fatal2("Encountered unexpected pre-existing sigaction handler %#lx for signal %d.", (long)oldhand, sig);
+      fatal(err_msg("Encountered unexpected pre-existing sigaction handler "
+                    "%#lx for signal %d.", (long)oldhand, sig));
     }
   }
 
@@ -4764,7 +4767,8 @@
 
   page_size = sysconf(_SC_PAGESIZE);
   if (page_size == -1)
-    fatal1("os_solaris.cpp: os::init: sysconf failed (%s)", strerror(errno));
+    fatal(err_msg("os_solaris.cpp: os::init: sysconf failed (%s)",
+                  strerror(errno)));
   init_page_sizes((size_t) page_size);
 
   Solaris::initialize_system_info();
@@ -4775,7 +4779,7 @@
 
   int fd = open("/dev/zero", O_RDWR);
   if (fd < 0) {
-    fatal1("os::init: cannot open /dev/zero (%s)", strerror(errno));
+    fatal(err_msg("os::init: cannot open /dev/zero (%s)", strerror(errno)));
   } else {
     Solaris::set_dev_zero_fd(fd);
 
--- a/src/os/solaris/vm/threadCritical_solaris.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/os/solaris/vm/threadCritical_solaris.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -47,7 +47,8 @@
     thread_t owner = thr_self();
     if (global_mut_owner != owner) {
       if (os::Solaris::mutex_lock(&global_mut))
-        fatal1("ThreadCritical::ThreadCritical: mutex_lock failed (%s)", strerror(errno));
+        fatal(err_msg("ThreadCritical::ThreadCritical: mutex_lock failed (%s)",
+                      strerror(errno)));
       assert(global_mut_count == 0, "must have clean count");
       assert(global_mut_owner == -1, "must have clean owner");
     }
@@ -66,7 +67,8 @@
     if (global_mut_count == 0) {
       global_mut_owner = -1;
       if (os::Solaris::mutex_unlock(&global_mut))
-        fatal1("ThreadCritical::~ThreadCritical: mutex_unlock failed (%s)", strerror(errno));
+        fatal(err_msg("ThreadCritical::~ThreadCritical: mutex_unlock failed "
+                      "(%s)", strerror(errno)));
     }
   } else {
     assert (Threads::number_of_threads() == 0, "valid only during initialization");
--- a/src/os/windows/vm/os_windows.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/os/windows/vm/os_windows.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -724,7 +724,7 @@
   java_origin.wMilliseconds  = 0;
   FILETIME jot;
   if (!SystemTimeToFileTime(&java_origin, &jot)) {
-    fatal1("Error = %d\nWindows error", GetLastError());
+    fatal(err_msg("Error = %d\nWindows error", GetLastError()));
   }
   _calculated_offset = jlong_from(jot.dwHighDateTime, jot.dwLowDateTime);
   _has_calculated_offset = 1;
@@ -4095,7 +4095,7 @@
       }
       int err = GetLastError();
       if (err != ERROR_NO_MORE_ITEMS && err != ERROR_CALL_NOT_IMPLEMENTED) {
-        fatal1("heap walk aborted with error %d", err);
+        fatal(err_msg("heap walk aborted with error %d", err));
       }
       HeapUnlock(heap);
     }
--- a/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -153,7 +153,7 @@
       if (rslt == ENOMEM) {
         vm_exit_out_of_memory(0, "pthread_getattr_np");
       } else {
-        fatal1("pthread_getattr_np failed with errno = %d", rslt);
+        fatal(err_msg("pthread_getattr_np failed with errno = %d", rslt));
       }
     }
 
--- a/src/os_cpu/linux_x86/vm/os_linux_x86.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/os_cpu/linux_x86/vm/os_linux_x86.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -680,7 +680,7 @@
        if (rslt == ENOMEM) {
          vm_exit_out_of_memory(0, "pthread_getattr_np");
        } else {
-         fatal1("pthread_getattr_np failed with errno = %d", rslt);
+         fatal(err_msg("pthread_getattr_np failed with errno = %d", rslt));
        }
      }
 
--- a/src/share/vm/asm/assembler.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/asm/assembler.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -43,7 +43,8 @@
   _code_pos    = cs->end();
   _oop_recorder= code->oop_recorder();
   if (_code_begin == NULL)  {
-    vm_exit_out_of_memory1(0, "CodeCache: no room for %s", code->name());
+    vm_exit_out_of_memory(0, err_msg("CodeCache: no room for %s",
+                                     code->name()));
   }
 }
 
--- a/src/share/vm/classfile/classFileParser.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/classfile/classFileParser.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -334,7 +334,8 @@
         }
         break;
       default:
-        fatal1("bad constant pool tag value %u", cp->tag_at(index).value());
+        fatal(err_msg("bad constant pool tag value %u",
+                      cp->tag_at(index).value()));
         ShouldNotReachHere();
         break;
     } // end of switch
--- a/src/share/vm/code/exceptionHandlerTable.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/code/exceptionHandlerTable.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -221,6 +221,6 @@
   for (uint i = 0; i < len(); i++) {
      if ((*adr(i) > (unsigned int)nm->code_size()) ||
          (*(adr(i)+1) > (unsigned int)nm->code_size()))
-       fatal1("Invalid offset in ImplicitExceptionTable at %lx", _data);
+       fatal(err_msg("Invalid offset in ImplicitExceptionTable at " PTR_FORMAT, _data));
   }
 }
--- a/src/share/vm/code/nmethod.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/code/nmethod.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -2124,7 +2124,7 @@
   ResourceMark rm;
 
   if (!CodeCache::contains(this)) {
-    fatal1("nmethod at " INTPTR_FORMAT " not in zone", this);
+    fatal(err_msg("nmethod at " INTPTR_FORMAT " not in zone", this));
   }
 
   if(is_native_method() )
@@ -2132,7 +2132,8 @@
 
   nmethod* nm = CodeCache::find_nmethod(verified_entry_point());
   if (nm != this) {
-    fatal1("findNMethod did not find this nmethod (" INTPTR_FORMAT ")", this);
+    fatal(err_msg("findNMethod did not find this nmethod (" INTPTR_FORMAT ")",
+                  this));
   }
 
   for (PcDesc* p = scopes_pcs_begin(); p < scopes_pcs_end(); p++) {
--- a/src/share/vm/code/stubs.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/code/stubs.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -62,7 +62,9 @@
                      Mutex* lock, const char* name) : _mutex(lock) {
   intptr_t size = round_to(buffer_size, 2*BytesPerWord);
   BufferBlob* blob = BufferBlob::create(name, size);
-  if( blob == NULL ) vm_exit_out_of_memory1(size, "CodeCache: no room for %s", name);
+  if( blob == NULL) {
+    vm_exit_out_of_memory(size, err_msg("CodeCache: no room for %s", name));
+  }
   _stub_interface  = stub_interface;
   _buffer_size     = blob->instructions_size();
   _buffer_limit    = blob->instructions_size();
--- a/src/share/vm/code/vtableStubs.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/code/vtableStubs.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -45,7 +45,9 @@
   if (_chunk == NULL || _chunk + real_size > _chunk_end) {
     const int bytes = chunk_factor * real_size + pd_code_alignment();
     BufferBlob* blob = BufferBlob::create("vtable chunks", bytes);
-    if( blob == NULL ) vm_exit_out_of_memory1(bytes, "CodeCache: no room for %s", "vtable chunks");
+    if (blob == NULL) {
+      vm_exit_out_of_memory(bytes, "CodeCache: no room for vtable chunks");
+    }
     _chunk = blob->instructions_begin();
     _chunk_end = _chunk + bytes;
     VTune::register_stub("vtable stub", _chunk, _chunk_end);
@@ -189,7 +191,9 @@
   instanceKlass* ik = instanceKlass::cast(klass);
   klassVtable* vt = ik->vtable();
   klass->print();
-  fatal3("bad compiled vtable dispatch: receiver " INTPTR_FORMAT ", index %d (vtable length %d)", (address)receiver, index, vt->length());
+  fatal(err_msg("bad compiled vtable dispatch: receiver " INTPTR_FORMAT ", "
+                "index %d (vtable length %d)",
+                (address)receiver, index, vt->length()));
 }
 
 #endif // Product
--- a/src/share/vm/interpreter/bytecodeInterpreter.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/interpreter/bytecodeInterpreter.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -2339,8 +2339,8 @@
               goto opcode_switch;
           }
 #endif
-          fatal2("\t*** Unimplemented opcode: %d = %s\n",
-                 opcode, Bytecodes::name((Bytecodes::Code)opcode));
+          fatal(err_msg("Unimplemented opcode %d = %s", opcode,
+                        Bytecodes::name((Bytecodes::Code)opcode)));
           goto finish;
 
       } /* switch(opc) */
--- a/src/share/vm/interpreter/bytecodes.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/interpreter/bytecodes.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -426,7 +426,9 @@
         if (is_defined(i)) {
           Code code = cast(i);
           Code java = java_code(code);
-          if (can_trap(code) && !can_trap(java)) fatal2("%s can trap => %s can trap, too", name(code), name(java));
+          if (can_trap(code) && !can_trap(java))
+            fatal(err_msg("%s can trap => %s can trap, too", name(code),
+                          name(java)));
         }
       }
     }
--- a/src/share/vm/oops/instanceKlass.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/oops/instanceKlass.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -966,7 +966,7 @@
       // not found
 #ifdef ASSERT
       int index = linear_search(methods, name, signature);
-      if (index != -1) fatal1("binary search bug: should have found entry %d", index);
+      assert(index == -1, err_msg("binary search should have found entry %d", index));
 #endif
       return NULL;
     } else if (res < 0) {
@@ -977,7 +977,7 @@
   }
 #ifdef ASSERT
   int index = linear_search(methods, name, signature);
-  if (index != -1) fatal1("binary search bug: should have found entry %d", index);
+  assert(index == -1, err_msg("binary search should have found entry %d", index));
 #endif
   return NULL;
 }
--- a/src/share/vm/oops/instanceKlassKlass.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/oops/instanceKlassKlass.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -712,10 +712,10 @@
     int sib_count = 0;
     while (sib != NULL) {
       if (sib == ik) {
-        fatal1("subclass cycle of length %d", sib_count);
+        fatal(err_msg("subclass cycle of length %d", sib_count));
       }
       if (sib_count >= 100000) {
-        fatal1("suspiciously long subclass list %d", sib_count);
+        fatal(err_msg("suspiciously long subclass list %d", sib_count));
       }
       guarantee(sib->as_klassOop()->is_klass(), "should be klass");
       guarantee(sib->as_klassOop()->is_perm(),  "should be in permspace");
--- a/src/share/vm/oops/klassVtable.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/oops/klassVtable.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -1180,8 +1180,8 @@
   oop* end_of_obj = (oop*)_klass() + _klass()->size();
   oop* end_of_vtable = (oop *)&table()[_length];
   if (end_of_vtable > end_of_obj) {
-    fatal1("klass %s: klass object too short (vtable extends beyond end)",
-          _klass->internal_name());
+    fatal(err_msg("klass %s: klass object too short (vtable extends beyond "
+                  "end)", _klass->internal_name()));
   }
 
   for (int i = 0; i < _length; i++) table()[i].verify(this, st);
@@ -1224,7 +1224,7 @@
 #ifndef PRODUCT
     print();
 #endif
-    fatal1("vtableEntry %#lx: method is from subclass", this);
+    fatal(err_msg("vtableEntry " PTR_FORMAT ": method is from subclass", this));
   }
 }
 
--- a/src/share/vm/opto/idealGraphPrinter.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/opto/idealGraphPrinter.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -151,7 +151,8 @@
     } else {
       // It would be nice if we could shut down cleanly but it should
       // be an error if we can't connect to the visualizer.
-      fatal2("Couldn't connect to visualizer at %s:%d", PrintIdealGraphAddress, PrintIdealGraphPort);
+      fatal(err_msg("Couldn't connect to visualizer at %s:%d",
+                    PrintIdealGraphAddress, PrintIdealGraphPort));
     }
   }
 
--- a/src/share/vm/opto/output.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/opto/output.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -2407,7 +2407,7 @@
       n->dump();
       tty->print_cr("...");
       prior_use->dump();
-      assert_msg(edge_from_to(prior_use,n),msg);
+      assert(edge_from_to(prior_use,n),msg);
     }
     _reg_node.map(def,NULL); // Kill live USEs
   }
@@ -2446,11 +2446,11 @@
       OptoReg::Name reg_lo = _regalloc->get_reg_first(def);
       OptoReg::Name reg_hi = _regalloc->get_reg_second(def);
       if( OptoReg::is_valid(reg_lo) ) {
-        assert_msg(!_reg_node[reg_lo] || edge_from_to(_reg_node[reg_lo],def), msg );
+        assert(!_reg_node[reg_lo] || edge_from_to(_reg_node[reg_lo],def), msg);
         _reg_node.map(reg_lo,n);
       }
       if( OptoReg::is_valid(reg_hi) ) {
-        assert_msg(!_reg_node[reg_hi] || edge_from_to(_reg_node[reg_hi],def), msg );
+        assert(!_reg_node[reg_hi] || edge_from_to(_reg_node[reg_hi],def), msg);
         _reg_node.map(reg_hi,n);
       }
     }
--- a/src/share/vm/prims/jni.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/prims/jni.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -3311,6 +3311,7 @@
     OrderAccess::release_store(&vm_created, 0);
   }
 
+  NOT_PRODUCT(test_error_handler(ErrorHandlerTest));
   return result;
 }
 
--- a/src/share/vm/runtime/globals.hpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/runtime/globals.hpp	Thu Apr 22 13:23:15 2010 -0700
@@ -652,6 +652,11 @@
   product(bool, PrintGCApplicationStoppedTime, false,                       \
           "Print the time the application has been stopped")                \
                                                                             \
+  notproduct(uintx, ErrorHandlerTest, 0,                                    \
+          "If > 0, provokes an error after VM initialization; the value"    \
+          "determines which error to provoke.  See test_error_handler()"    \
+          "in debug.cpp.")                                                  \
+                                                                            \
   develop(bool, Verbose, false,                                             \
           "Prints additional debugging information from other modes")       \
                                                                             \
--- a/src/share/vm/runtime/memprofiler.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/runtime/memprofiler.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -62,7 +62,7 @@
     // Create log file
     _log_fp = fopen(log_name , "w+");
     if (_log_fp == NULL) {
-      fatal1("MemProfiler: Cannot create log file: %s", log_name);
+      fatal(err_msg("MemProfiler: Cannot create log file: %s", log_name));
     }
     fprintf(_log_fp, "MemProfiler: sizes are in Kb, time is in seconds since startup\n\n");
     fprintf(_log_fp, "  time, #thr, #cls,  heap,  heap,  perm,  perm,  code, hndls, rescs, oopmp\n");
--- a/src/share/vm/runtime/mutex.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/runtime/mutex.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -1288,8 +1288,9 @@
           !(this == Safepoint_lock && contains(locks, Terminator_lock) &&
             SafepointSynchronize::is_synchronizing())) {
         new_owner->print_owned_locks();
-        fatal4("acquiring lock %s/%d out of order with lock %s/%d -- possible deadlock",
-               this->name(), this->rank(), locks->name(), locks->rank());
+        fatal(err_msg("acquiring lock %s/%d out of order with lock %s/%d -- "
+                      "possible deadlock", this->name(), this->rank(),
+                      locks->name(), locks->rank()));
       }
 
       this->_next = new_owner->_owned_locks;
@@ -1342,7 +1343,8 @@
          || rank() == Mutex::special, "wrong thread state for using locks");
   if (StrictSafepointChecks) {
     if (thread->is_VM_thread() && !allow_vm_block()) {
-      fatal1("VM thread using lock %s (not allowed to block on)", name());
+      fatal(err_msg("VM thread using lock %s (not allowed to block on)",
+                    name()));
     }
     debug_only(if (rank() != Mutex::special) \
       thread->check_for_valid_safepoint_state(false);)
--- a/src/share/vm/runtime/mutexLocker.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/runtime/mutexLocker.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -136,7 +136,7 @@
   // see if invoker of VM operation owns it
   VM_Operation* op = VMThread::vm_operation();
   if (op != NULL && op->calling_thread() == lock->owner()) return;
-  fatal1("must own lock %s", lock->name());
+  fatal(err_msg("must own lock %s", lock->name()));
 }
 
 // a stronger assertion than the above
@@ -144,7 +144,7 @@
   if (IgnoreLockingAssertions) return;
   assert(lock != NULL, "Need non-NULL lock");
   if (lock->owned_by_self()) return;
-  fatal1("must own lock %s", lock->name());
+  fatal(err_msg("must own lock %s", lock->name()));
 }
 #endif
 
--- a/src/share/vm/runtime/os.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/runtime/os.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -406,8 +406,10 @@
 #ifdef ASSERT
 inline size_t get_size(void* obj) {
   size_t size = *size_addr_from_obj(obj);
-  if (size < 0 )
-    fatal2("free: size field of object #%p was overwritten (%lu)", obj, size);
+  if (size < 0) {
+    fatal(err_msg("free: size field of object #" PTR_FORMAT " was overwritten ("
+                  SIZE_FORMAT ")", obj, size));
+  }
   return size;
 }
 
--- a/src/share/vm/runtime/safepoint.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/runtime/safepoint.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -594,7 +594,7 @@
       break;
 
     default:
-     fatal1("Illegal threadstate encountered: %d", state);
+     fatal(err_msg("Illegal threadstate encountered: %d", state));
   }
 
   // Check for pending. async. exceptions or suspends - except if the
--- a/src/share/vm/runtime/signature.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/runtime/signature.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -57,7 +57,7 @@
 }
 
 void SignatureIterator::expect(char c) {
-  if (_signature->byte_at(_index) != c) fatal1("expecting %c", c);
+  if (_signature->byte_at(_index) != c) fatal(err_msg("expecting %c", c));
   _index++;
 }
 
--- a/src/share/vm/runtime/stubRoutines.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/runtime/stubRoutines.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -118,7 +118,10 @@
     ResourceMark rm;
     TraceTime timer("StubRoutines generation 1", TraceStartupTime);
     _code1 = BufferBlob::create("StubRoutines (1)", code_size1);
-    if( _code1 == NULL) vm_exit_out_of_memory1(code_size1, "CodeCache: no room for %s", "StubRoutines (1)");
+    if (_code1 == NULL) {
+      vm_exit_out_of_memory(code_size1,
+                            "CodeCache: no room for StubRoutines (1)");
+    }
     CodeBuffer buffer(_code1->instructions_begin(), _code1->instructions_size());
     StubGenerator_generate(&buffer, false);
   }
@@ -164,7 +167,10 @@
     ResourceMark rm;
     TraceTime timer("StubRoutines generation 2", TraceStartupTime);
     _code2 = BufferBlob::create("StubRoutines (2)", code_size2);
-    if( _code2 == NULL) vm_exit_out_of_memory1(code_size2, "CodeCache: no room for %s", "StubRoutines (2)");
+    if (_code2 == NULL) {
+      vm_exit_out_of_memory(code_size2,
+                            "CodeCache: no room for StubRoutines (2)");
+    }
     CodeBuffer buffer(_code2->instructions_begin(), _code2->instructions_size());
     StubGenerator_generate(&buffer, true);
   }
--- a/src/share/vm/runtime/vmThread.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/runtime/vmThread.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -593,7 +593,8 @@
       // Check the VM operation allows nested VM operation. This normally not the case, e.g., the compiler
       // does not allow nested scavenges or compiles.
       if (!prev_vm_operation->allow_nested_vm_operations()) {
-        fatal2("Nested VM operation %s requested by operation %s", op->name(), vm_operation()->name());
+        fatal(err_msg("Nested VM operation %s requested by operation %s",
+                      op->name(), vm_operation()->name()));
       }
       op->set_calling_thread(prev_vm_operation->calling_thread(), prev_vm_operation->priority());
     }
--- a/src/share/vm/utilities/debug.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/utilities/debug.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -72,7 +72,7 @@
 // assert/guarantee/... may happen very early during VM initialization.
 // Don't rely on anything that is initialized by Threads::create_vm(). For
 // example, don't use tty.
-bool assert_is_suppressed(const char* file_name, int line_no) {
+bool error_is_suppressed(const char* file_name, int line_no) {
   // The following 1-element cache requires that passed-in
   // file names are always only constant literals.
   if (file_name == last_file_name && line_no == last_line_no)  return true;
@@ -163,38 +163,30 @@
 #else
 
 // Place-holder for non-existent suppression check:
-#define assert_is_suppressed(file_name, line_no) (false)
+#define error_is_suppressed(file_name, line_no) (false)
 
 #endif //PRODUCT
 
-void report_assertion_failure(const char* file_name, int line_no, const char* message) {
-  if (Debugging || assert_is_suppressed(file_name, line_no))  return;
-  VMError err(ThreadLocalStorage::get_thread_slow(), message, file_name, line_no);
+void report_vm_error(const char* file, int line, const char* error_msg,
+                     const char* detail_msg)
+{
+  if (Debugging || error_is_suppressed(file, line)) return;
+  Thread* const thread = ThreadLocalStorage::get_thread_slow();
+  VMError err(thread, file, line, error_msg, detail_msg);
   err.report_and_die();
 }
 
-void report_fatal(const char* file_name, int line_no, const char* message) {
-  if (Debugging || assert_is_suppressed(file_name, line_no))  return;
-  VMError err(ThreadLocalStorage::get_thread_slow(), message, file_name, line_no);
-  err.report_and_die();
+void report_fatal(const char* file, int line, const char* message)
+{
+  report_vm_error(file, line, "fatal error", message);
 }
 
-void report_fatal_vararg(const char* file_name, int line_no, const char* format, ...) {
-  char buffer[256];
-  va_list ap;
-  va_start(ap, format);
-  jio_vsnprintf(buffer, sizeof(buffer), format, ap);
-  va_end(ap);
-  report_fatal(file_name, line_no, buffer);
-}
-
-
 // Used by report_vm_out_of_memory to detect recursion.
 static jint _exiting_out_of_mem = 0;
 
-// Just passing the flow to VMError to handle error
-void report_vm_out_of_memory(const char* file_name, int line_no, size_t size, const char* message) {
-  if (Debugging || assert_is_suppressed(file_name, line_no))  return;
+void report_vm_out_of_memory(const char* file, int line, size_t size,
+                             const char* message) {
+  if (Debugging || error_is_suppressed(file, line)) return;
 
   // We try to gather additional information for the first out of memory
   // error only; gathering additional data might cause an allocation and a
@@ -206,46 +198,28 @@
 
   if (first_time_here) {
     Thread* thread = ThreadLocalStorage::get_thread_slow();
-    VMError(thread, size, message, file_name, line_no).report_and_die();
+    VMError(thread, file, line, size, message).report_and_die();
   }
 
   // Dump core and abort
   vm_abort(true);
 }
 
-void report_vm_out_of_memory_vararg(const char* file_name, int line_no, size_t size, const char* format, ...) {
-  char buffer[256];
-  va_list ap;
-  va_start(ap, format);
-  jio_vsnprintf(buffer, sizeof(buffer), format, ap);
-  va_end(ap);
-  report_vm_out_of_memory(file_name, line_no, size, buffer);
+void report_should_not_call(const char* file, int line) {
+  report_vm_error(file, line, "ShouldNotCall()");
 }
 
-void report_should_not_call(const char* file_name, int line_no) {
-  if (Debugging || assert_is_suppressed(file_name, line_no))  return;
-  VMError err(ThreadLocalStorage::get_thread_slow(), "ShouldNotCall()", file_name, line_no);
-  err.report_and_die();
+void report_should_not_reach_here(const char* file, int line) {
+  report_vm_error(file, line, "ShouldNotReachHere()");
 }
 
-
-void report_should_not_reach_here(const char* file_name, int line_no) {
-  if (Debugging || assert_is_suppressed(file_name, line_no))  return;
-  VMError err(ThreadLocalStorage::get_thread_slow(), "ShouldNotReachHere()", file_name, line_no);
-  err.report_and_die();
+void report_unimplemented(const char* file, int line) {
+  report_vm_error(file, line, "Unimplemented()");
 }
 
-
-void report_unimplemented(const char* file_name, int line_no) {
-  if (Debugging || assert_is_suppressed(file_name, line_no))  return;
-  VMError err(ThreadLocalStorage::get_thread_slow(), "Unimplemented()", file_name, line_no);
-  err.report_and_die();
-}
-
-
-void report_untested(const char* file_name, int line_no, const char* msg) {
+void report_untested(const char* file, int line, const char* message) {
 #ifndef PRODUCT
-  warning("Untested: %s in %s: %d\n", msg, file_name, line_no);
+  warning("Untested: %s in %s: %d\n", message, file, line);
 #endif // PRODUCT
 }
 
@@ -284,6 +258,51 @@
     return error_reported;
 }
 
+#ifndef PRODUCT
+#include <signal.h>
+
+void test_error_handler(size_t test_num)
+{
+  if (test_num == 0) return;
+
+  // If asserts are disabled, use the corresponding guarantee instead.
+  size_t n = test_num;
+  NOT_DEBUG(if (n <= 2) n += 2);
+
+  const char* const str = "hello";
+  const size_t      num = (size_t)os::vm_page_size();
+
+  const char* const eol = os::line_separator();
+  const char* const msg = "this message should be truncated during formatting";
+
+  // Keep this in sync with test/runtime/6888954/vmerrors.sh.
+  switch (n) {
+    case  1: assert(str == NULL, "expected null");
+    case  2: assert(num == 1023 && *str == 'X',
+                    err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str));
+    case  3: guarantee(str == NULL, "expected null");
+    case  4: guarantee(num == 1023 && *str == 'X',
+                       err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str));
+    case  5: fatal("expected null");
+    case  6: fatal(err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str));
+    case  7: fatal(err_msg("%s%s#    %s%s#    %s%s#    %s%s#    %s%s#    "
+                           "%s%s#    %s%s#    %s%s#    %s%s#    %s%s#    "
+                           "%s%s#    %s%s#    %s%s#    %s%s#    %s",
+                           msg, eol, msg, eol, msg, eol, msg, eol, msg, eol,
+                           msg, eol, msg, eol, msg, eol, msg, eol, msg, eol,
+                           msg, eol, msg, eol, msg, eol, msg, eol, msg));
+    case  8: vm_exit_out_of_memory(num, "ChunkPool::allocate");
+    case  9: ShouldNotCallThis();
+    case 10: ShouldNotReachHere();
+    case 11: Unimplemented();
+    // This is last because it does not generate an hs_err* file on Windows.
+    case 12: os::signal_raise(SIGSEGV);
+
+    default: ShouldNotReachHere();
+  }
+}
+#endif // #ifndef PRODUCT
+
 // ------ helper functions for debugging go here ------------
 
 #ifndef PRODUCT
--- a/src/share/vm/utilities/debug.hpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/utilities/debug.hpp	Thu Apr 22 13:23:15 2010 -0700
@@ -22,28 +22,54 @@
  *
  */
 
+#include <stdarg.h>
+
+// Simple class to format the ctor arguments into a fixed-sized buffer.
+template <size_t bufsz = 256>
+class FormatBuffer {
+public:
+  inline FormatBuffer(const char * format, ...);
+  operator const char *() const { return _buf; }
+
+private:
+  FormatBuffer(const FormatBuffer &); // prevent copies
+
+private:
+  char _buf[bufsz];
+};
+
+template <size_t bufsz>
+FormatBuffer<bufsz>::FormatBuffer(const char * format, ...) {
+  va_list argp;
+  va_start(argp, format);
+  vsnprintf(_buf, bufsz, format, argp);
+  va_end(argp);
+}
+
+// Used to format messages for assert(), guarantee(), fatal(), etc.
+typedef FormatBuffer<> err_msg;
+
 // assertions
 #ifdef ASSERT
-// Turn this off by default:
-//#define USE_REPEATED_ASSERTS
-#ifdef USE_REPEATED_ASSERTS
-  #define assert(p,msg)                                              \
-    { for (int __i = 0; __i < AssertRepeat; __i++) {                 \
-        if (!(p)) {                                                  \
-          report_assertion_failure(__FILE__, __LINE__,               \
-                                  "assert(" XSTR(p) ",\"" msg "\")");\
-          BREAKPOINT;                                                \
-        }                                                            \
-      }                                                              \
-    }
-#else
-  #define assert(p,msg)                                          \
-    if (!(p)) {                                                  \
-      report_assertion_failure(__FILE__, __LINE__,               \
-                              "assert(" XSTR(p) ",\"" msg "\")");\
-      BREAKPOINT;                                                \
-    }
-#endif
+#ifndef USE_REPEATED_ASSERTS
+#define assert(p, msg)                                                       \
+do {                                                                         \
+  if (!(p)) {                                                                \
+    report_vm_error(__FILE__, __LINE__, "assert(" #p ") failed", msg);       \
+    BREAKPOINT;                                                              \
+  }                                                                          \
+} while (0)
+#else // #ifndef USE_REPEATED_ASSERTS
+#define assert(p, msg)
+do {                                                                         \
+  for (int __i = 0; __i < AssertRepeat; __i++) {                             \
+    if (!(p)) {                                                              \
+      report_vm_error(__FILE__, __LINE__, "assert(" #p ") failed", msg);     \
+      BREAKPOINT;                                                            \
+    }                                                                        \
+  }                                                                          \
+} while (0)
+#endif // #ifndef USE_REPEATED_ASSERTS
 
 // This version of assert is for use with checking return status from
 // library calls that return actual error values eg. EINVAL,
@@ -52,70 +78,83 @@
 // what status was actually returned, so we pass the status variable as
 // an extra arg and use strerror to convert it to a meaningful string
 // like "Invalid argument", "out of memory" etc
-#define assert_status(p, status, msg)                                     \
-   do {                                                                   \
-    if (!(p)) {                                                           \
-      char buf[128];                                                      \
-      snprintf(buf, 127,                                                  \
-               "assert_status(" XSTR(p) ", error: %s(%d), \"" msg "\")" , \
-               strerror((status)), (status));                             \
-      report_assertion_failure(__FILE__, __LINE__, buf);                  \
-      BREAKPOINT;                                                         \
-    }                                                                     \
-  } while (0)
-
-// Another version of assert where the message is not a string literal
-// The boolean condition is not printed out because cpp doesn't like it.
-#define assert_msg(p, msg)                                       \
-    if (!(p)) {                                                  \
-      report_assertion_failure(__FILE__, __LINE__, msg);         \
-      BREAKPOINT;                                                \
-    }
+#define assert_status(p, status, msg)                                        \
+do {                                                                         \
+  if (!(p)) {                                                                \
+    report_vm_error(__FILE__, __LINE__, "assert(" #p ") failed",             \
+                    err_msg("error %s(%d) %s", strerror(status),             \
+                            status, msg));                                   \
+    BREAKPOINT;                                                              \
+  }                                                                          \
+} while (0)
 
 // Do not assert this condition if there's already another error reported.
 #define assert_if_no_error(cond,msg) assert((cond) || is_error_reported(), msg)
-#else
+#else // #ifdef ASSERT
   #define assert(p,msg)
   #define assert_status(p,status,msg)
   #define assert_if_no_error(cond,msg)
-  #define assert_msg(cond,msg)
-#endif
+#endif // #ifdef ASSERT
 
+// guarantee is like assert except it's always executed -- use it for
+// cheap tests that catch errors that would otherwise be hard to find.
+// guarantee is also used for Verify options.
+#define guarantee(p, msg)                                                    \
+do {                                                                         \
+  if (!(p)) {                                                                \
+    report_vm_error(__FILE__, __LINE__, "guarantee(" #p ") failed", msg);    \
+    BREAKPOINT;                                                              \
+  }                                                                          \
+} while (0)
 
-// fatals
-#define fatal(m)                             { report_fatal(__FILE__, __LINE__, m                          ); BREAKPOINT; }
-#define fatal1(m,x1)                         { report_fatal_vararg(__FILE__, __LINE__, m, x1               ); BREAKPOINT; }
-#define fatal2(m,x1,x2)                      { report_fatal_vararg(__FILE__, __LINE__, m, x1, x2           ); BREAKPOINT; }
-#define fatal3(m,x1,x2,x3)                   { report_fatal_vararg(__FILE__, __LINE__, m, x1, x2, x3       ); BREAKPOINT; }
-#define fatal4(m,x1,x2,x3,x4)                { report_fatal_vararg(__FILE__, __LINE__, m, x1, x2, x3, x4   ); BREAKPOINT; }
+#define fatal(msg)                                                           \
+do {                                                                         \
+  report_fatal(__FILE__, __LINE__, msg);                                     \
+  BREAKPOINT;                                                                \
+} while (0)
 
 // out of memory
-#define vm_exit_out_of_memory(s,m)              { report_vm_out_of_memory(__FILE__, __LINE__, s, m                       ); BREAKPOINT; }
-#define vm_exit_out_of_memory1(s,m,x1)          { report_vm_out_of_memory_vararg(__FILE__, __LINE__, s, m, x1            ); BREAKPOINT; }
-#define vm_exit_out_of_memory2(s,m,x1,x2)       { report_vm_out_of_memory_vararg(__FILE__, __LINE__, s, m, x1, x2        ); BREAKPOINT; }
-#define vm_exit_out_of_memory3(s,m,x1,x2,x3)    { report_vm_out_of_memory_vararg(__FILE__, __LINE__, s, m, x1, x2, x3    ); BREAKPOINT; }
-#define vm_exit_out_of_memory4(s,m,x1,x2,x3,x4) { report_vm_out_of_memory_vararg(__FILE__, __LINE__, s, m, x1, x2, x3, x4); BREAKPOINT; }
+#define vm_exit_out_of_memory(size, msg)                                     \
+do {                                                                         \
+  report_vm_out_of_memory(__FILE__, __LINE__, size, msg);                    \
+  BREAKPOINT;                                                                \
+} while (0)
 
-// guarantee is like assert except it's always executed -- use it for
-// cheap tests that catch errors that would otherwise be hard to find
-// guarantee is also used for Verify options.
-#define guarantee(b,msg)         { if (!(b)) fatal("guarantee(" XSTR(b) ",\"" msg "\")"); }
+#define ShouldNotCallThis()                                                  \
+do {                                                                         \
+  report_should_not_call(__FILE__, __LINE__);                                \
+  BREAKPOINT;                                                                \
+} while (0)
 
-#define ShouldNotCallThis()      { report_should_not_call        (__FILE__, __LINE__); BREAKPOINT; }
-#define ShouldNotReachHere()     { report_should_not_reach_here  (__FILE__, __LINE__); BREAKPOINT; }
-#define Unimplemented()          { report_unimplemented          (__FILE__, __LINE__); BREAKPOINT; }
-#define Untested(msg)            { report_untested               (__FILE__, __LINE__, msg); BREAKPOINT; }
+#define ShouldNotReachHere()                                                 \
+do {                                                                         \
+  report_should_not_reach_here(__FILE__, __LINE__);                          \
+  BREAKPOINT;                                                                \
+} while (0)
+
+#define Unimplemented()                                                      \
+do {                                                                         \
+  report_unimplemented(__FILE__, __LINE__);                                  \
+  BREAKPOINT;                                                                \
+} while (0)
+
+#define Untested(msg)                                                        \
+do {                                                                         \
+  report_untested(__FILE__, __LINE__, msg);                                  \
+  BREAKPOINT;                                                                \
+} while (0);
 
 // error reporting helper functions
-void report_assertion_failure(const char* file_name, int line_no, const char* message);
-void report_fatal_vararg(const char* file_name, int line_no, const char* format, ...);
-void report_fatal(const char* file_name, int line_no, const char* message);
-void report_vm_out_of_memory_vararg(const char* file_name, int line_no, size_t size, const char* format, ...);
-void report_vm_out_of_memory(const char* file_name, int line_no, size_t size, const char* message);
-void report_should_not_call(const char* file_name, int line_no);
-void report_should_not_reach_here(const char* file_name, int line_no);
-void report_unimplemented(const char* file_name, int line_no);
-void report_untested(const char* file_name, int line_no, const char* msg);
+void report_vm_error(const char* file, int line, const char* error_msg,
+                     const char* detail_msg = NULL);
+void report_fatal(const char* file, int line, const char* message);
+void report_vm_out_of_memory(const char* file, int line, size_t size,
+                             const char* message);
+void report_should_not_call(const char* file, int line);
+void report_should_not_reach_here(const char* file, int line);
+void report_unimplemented(const char* file, int line);
+void report_untested(const char* file, int line, const char* message);
+
 void warning(const char* format, ...);
 
 // out of memory reporting
@@ -125,5 +164,8 @@
 bool is_error_reported();
 void set_error_reported();
 
+/* Test assert(), fatal(), guarantee(), etc. */
+NOT_PRODUCT(void test_error_handler(size_t test_num);)
+
 void pd_ps(frame f);
 void pd_obfuscate_location(char *buf, size_t buflen);
--- a/src/share/vm/utilities/exceptions.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/utilities/exceptions.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -378,7 +378,7 @@
 void Exceptions::debug_check_abort(const char *value_string) {
   if (AbortVMOnException != NULL && value_string != NULL &&
       strstr(value_string, AbortVMOnException)) {
-    fatal1("Saw %s, aborting", value_string);
+    fatal(err_msg("Saw %s, aborting", value_string));
   }
 }
 
--- a/src/share/vm/utilities/macros.hpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/utilities/macros.hpp	Thu Apr 22 13:23:15 2010 -0700
@@ -188,6 +188,4 @@
 #define NOT_SPARC(code) code
 #endif
 
-#define FIX_THIS(code) report_assertion_failure("FIX_THIS",__FILE__, __LINE__, "")
-
 #define define_pd_global(type, name, value) const type pd_##name = value;
--- a/src/share/vm/utilities/vmError.cpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/utilities/vmError.cpp	Thu Apr 22 13:23:15 2010 -0700
@@ -65,7 +65,8 @@
     _current_step = 0;
     _current_step_info = NULL;
 
-    _message = "";
+    _message = NULL;
+    _detail_msg = NULL;
     _filename = NULL;
     _lineno = 0;
 
@@ -73,31 +74,36 @@
 }
 
 // Constructor for internal errors
-VMError::VMError(Thread* thread, const char* message, const char* filename, int lineno) {
+VMError::VMError(Thread* thread, const char* filename, int lineno,
+                 const char* message, const char * detail_msg)
+{
+  _thread = thread;
+  _id = internal_error;     // Value that's not an OS exception/signal
+  _filename = filename;
+  _lineno = lineno;
+  _message = message;
+  _detail_msg = detail_msg;
+
+  _verbose = false;
+  _current_step = 0;
+  _current_step_info = NULL;
+
+  _pc = NULL;
+  _siginfo = NULL;
+  _context = NULL;
+
+  _size = 0;
+}
+
+// Constructor for OOM errors
+VMError::VMError(Thread* thread, const char* filename, int lineno, size_t size,
+                 const char* message) {
     _thread = thread;
-    _id = internal_error;     // set it to a value that's not an OS exception/signal
+    _id = oom_error;     // Value that's not an OS exception/signal
     _filename = filename;
     _lineno = lineno;
     _message = message;
-
-    _verbose = false;
-    _current_step = 0;
-    _current_step_info = NULL;
-
-    _pc = NULL;
-    _siginfo = NULL;
-    _context = NULL;
-
-    _size = 0;
-}
-
-// Constructor for OOM errors
-VMError::VMError(Thread* thread, size_t size, const char* message, const char* filename, int lineno) {
-    _thread = thread;
-    _id = oom_error;     // set it to a value that's not an OS exception/signal
-    _filename = filename;
-    _lineno = lineno;
-    _message = message;
+    _detail_msg = NULL;
 
     _verbose = false;
     _current_step = 0;
@@ -114,10 +120,11 @@
 // Constructor for non-fatal errors
 VMError::VMError(const char* message) {
     _thread = NULL;
-    _id = internal_error;     // set it to a value that's not an OS exception/signal
+    _id = internal_error;     // Value that's not an OS exception/signal
     _filename = NULL;
     _lineno = 0;
     _message = message;
+    _detail_msg = NULL;
 
     _verbose = false;
     _current_step = 0;
@@ -191,22 +198,27 @@
                  "%s (0x%x) at pc=" PTR_FORMAT ", pid=%d, tid=" UINTX_FORMAT,
                  signame, _id, _pc,
                  os::current_process_id(), os::current_thread_id());
+  } else if (_filename != NULL && _lineno > 0) {
+    // skip directory names
+    char separator = os::file_separator()[0];
+    const char *p = strrchr(_filename, separator);
+    int n = jio_snprintf(buf, buflen,
+                         "Internal Error at %s:%d, pid=%d, tid=" UINTX_FORMAT,
+                         p ? p + 1 : _filename, _lineno,
+                         os::current_process_id(), os::current_thread_id());
+    if (n >= 0 && n < buflen && _message) {
+      if (_detail_msg) {
+        jio_snprintf(buf + n, buflen - n, "%s%s: %s",
+                     os::line_separator(), _message, _detail_msg);
+      } else {
+        jio_snprintf(buf + n, buflen - n, "%sError: %s",
+                     os::line_separator(), _message);
+      }
+    }
   } else {
-    if (_filename != NULL && _lineno > 0) {
-      // skip directory names
-      char separator = os::file_separator()[0];
-      const char *p = strrchr(_filename, separator);
-
-      jio_snprintf(buf, buflen,
-        "Internal Error at %s:%d, pid=%d, tid=" UINTX_FORMAT " \nError: %s",
-        p ? p + 1 : _filename, _lineno,
-        os::current_process_id(), os::current_thread_id(),
-        _message ? _message : "");
-    } else {
-      jio_snprintf(buf, buflen,
-        "Internal Error (0x%x), pid=%d, tid=" UINTX_FORMAT,
-        _id, os::current_process_id(), os::current_thread_id());
-    }
+    jio_snprintf(buf, buflen,
+                 "Internal Error (0x%x), pid=%d, tid=" UINTX_FORMAT,
+                 _id, os::current_process_id(), os::current_thread_id());
   }
 
   return buf;
@@ -369,7 +381,9 @@
   STEP(40, "(printing error message)")
 
      // error message
-     if (_message && _message[0] != '\0') {
+     if (_detail_msg) {
+       st->print_cr("#  %s: %s", _message ? _message : "Error", _detail_msg);
+     } else if (_message) {
        st->print_cr("#  Error: %s", _message);
      }
 
--- a/src/share/vm/utilities/vmError.hpp	Sun Oct 11 16:19:25 2009 -0700
+++ b/src/share/vm/utilities/vmError.hpp	Thu Apr 22 13:23:15 2010 -0700
@@ -37,6 +37,7 @@
                              //                     0x8xxxxxxx system warnings
 
   const char * _message;
+  const char * _detail_msg;
 
   Thread *     _thread;      // NULL if it's native thread
 
@@ -75,16 +76,19 @@
                                 char* buf, int buflen, bool verbose = false);
 
   // accessor
-  const char* message()         { return _message; }
+  const char* message() const    { return _message; }
+  const char* detail_msg() const { return _detail_msg; }
 
 public:
   // Constructor for crashes
   VMError(Thread* thread, int sig, address pc, void* siginfo, void* context);
   // Constructor for VM internal errors
-  VMError(Thread* thread, const char* message, const char* filename, int lineno);
+  VMError(Thread* thread, const char* filename, int lineno,
+          const char* message, const char * detail_msg);
 
-  // Constructors for VM OOM errors
-  VMError(Thread* thread, size_t size, const char* message, const char* filename, int lineno);
+  // Constructor for VM OOM errors
+  VMError(Thread* thread, const char* filename, int lineno, size_t size,
+          const char* message);
   // Constructor for non-fatal errors
   VMError(const char* message);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/runtime/6888954/vmerrors.sh	Thu Apr 22 13:23:15 2010 -0700
@@ -0,0 +1,71 @@
+# @test
+# @bug 6888954
+# @summary exercise HotSpot error handling code
+# @author John Coomes
+# @run shell vmerrors.sh
+
+# Repeatedly invoke java with a command-line option that causes HotSpot to
+# produce an error report and terminate just after initialization.  Each
+# invocation is identified by a small integer, <n>, which provokes a different
+# error (assertion failure, guarantee failure, fatal error, etc.).  The output
+# from stdout/stderr is written to <n>.out and the hs_err_pidXXX.log file is
+# renamed to <n>.log.
+#
+# The automated checking done by this script is minimal.  When updating the
+# fatal error handler it is more useful to run it manually or to use the -retain
+# option with the jtreg so that test directories are not removed automatically.
+# To run stand-alone:
+#
+# TESTJAVA=/java/home/dir
+# TESTVMOPTS=...
+# export TESTJAVA TESTVMOPTS
+# sh test/runtime/6888954/vmerrors.sh
+
+ulimit -c 0 # no core files
+
+i=1
+rc=0
+
+assert_re='(assert|guarantee)[(](str|num).*failed: *'
+guarantee_re='guarantee[(](str|num).*failed: *'
+fatal_re='fatal error: *'
+signal_re='(SIGSEGV|EXCEPTION_ACCESS_VIOLATION).* at pc='
+tail_1='.*expected null'
+tail_2='.*num='
+
+for re in                                                 \
+    "${assert_re}${tail_1}"    "${assert_re}${tail_2}"    \
+    "${guarantee_re}${tail_1}" "${guarantee_re}${tail_2}" \
+    "${fatal_re}${tail_1}"     "${fatal_re}${tail_2}"     \
+    "${fatal_re}.*truncated"   "ChunkPool::allocate"      \
+    "ShouldNotCall"            "ShouldNotReachHere"       \
+    "Unimplemented"            "$signal_re"
+    
+do
+    i2=$i
+    [ $i -lt 10 ] && i2=0$i
+
+    "$TESTJAVA/bin/java" $TESTVMOPTS -XX:+IgnoreUnrecognizedVMOptions \
+        -XX:ErrorHandlerTest=${i} -version > ${i2}.out 2>&1
+
+    # If ErrorHandlerTest is ignored (product build), stop.
+    #
+    # Using the built-in variable $! to get the pid does not work reliably on
+    # windows; use a wildcard instead.
+    mv hs_err_pid*.log ${i2}.log || exit $rc
+
+    for f in ${i2}.log ${i2}.out
+    do
+        egrep -- "$re" $f > $$
+        if [ $? -ne 0 ]
+        then
+            echo "ErrorHandlerTest=$i failed ($f)"
+            rc=1
+        fi
+    done
+    rm -f $$
+
+    i=$(expr $i + 1)
+done
+
+exit $rc