changeset 4425:d90c913b8103 hs24-b41

Merge
author amurillo
date Thu, 18 Apr 2013 13:42:00 -0700
parents 00144225e0dd 0e9dba751d8b
children c11b058d4170
files
diffstat 34 files changed, 492 insertions(+), 140 deletions(-) [+]
line wrap: on
line diff
--- a/agent/src/os/bsd/MacosxDebuggerLocal.m	Wed Apr 17 12:13:28 2013 -0700
+++ b/agent/src/os/bsd/MacosxDebuggerLocal.m	Thu Apr 18 13:42:00 2013 -0700
@@ -90,7 +90,8 @@
  * Method:    init0
  * Signature: ()V
  */
-JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_init0(JNIEnv *env, jclass cls) {
+JNIEXPORT void JNICALL 
+Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_init0(JNIEnv *env, jclass cls) {
   symbolicatorID = (*env)->GetFieldID(env, cls, "symbolicator", "J");
   taskID = (*env)->GetFieldID(env, cls, "task", "J");
   CHECK_EXCEPTION;
@@ -101,7 +102,11 @@
  * Method:    lookupByName0
  * Signature: (Ljava/lang/String;Ljava/lang/String;)J
  */
-JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0(JNIEnv *env, jobject this_obj, jstring objectName, jstring symbolName) {
+JNIEXPORT jlong JNICALL 
+Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0(
+  JNIEnv *env, jobject this_obj, 
+  jstring objectName, jstring symbolName) 
+{
   jlong address = 0;
 
 JNF_COCOA_ENTER(env);
@@ -130,7 +135,11 @@
  * Method:    readBytesFromProcess0
  * Signature: (JJ)Lsun/jvm/hotspot/debugger/ReadResult;
  */
-JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0(JNIEnv *env, jobject this_obj, jlong addr, jlong numBytes) {
+JNIEXPORT jbyteArray JNICALL
+Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0(
+  JNIEnv *env, jobject this_obj, 
+  jlong addr, jlong numBytes) 
+{
   if (debug) printf("readBytesFromProcess called. addr = %llx numBytes = %lld\n", addr, numBytes);
 
   // must allocate storage instead of using former parameter buf
@@ -202,12 +211,74 @@
   return array;
 }
 
+
 /*
- * Class:     sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal
+ * Lookup the thread_t that corresponds to the given thread_id.
+ * The thread_id should be the result from calling thread_info() with THREAD_IDENTIFIER_INFO
+ * and reading the m_ident_info.thread_id returned.
+ * The returned thread_t is the mach send right to the kernel port for the corresponding thread.
+ *
+ * We cannot simply use the OSThread._thread_id field in the JVM. This is set to ::mach_thread_self()
+ * in the VM, but that thread port is not valid for a remote debugger to access the thread.
+ */
+thread_t
+lookupThreadFromThreadId(task_t task, jlong thread_id) {
+  if (debug) {
+    printf("lookupThreadFromThreadId thread_id=0x%llx\n", thread_id);
+  }
+  
+  thread_array_t thread_list = NULL;
+  mach_msg_type_number_t thread_list_count = 0;
+  thread_t result_thread = 0;
+  int i;
+  
+  // get the list of all the send rights
+  kern_return_t result = task_threads(task, &thread_list, &thread_list_count);
+  if (result != KERN_SUCCESS) {
+    if (debug) {
+      printf("task_threads returned 0x%x\n", result);
+    }
+    return 0;
+  }
+  
+  for(i = 0 ; i < thread_list_count; i++) {
+    thread_identifier_info_data_t m_ident_info;
+    mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
+
+    // get the THREAD_IDENTIFIER_INFO for the send right
+    result = thread_info(thread_list[i], THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count);
+    if (result != KERN_SUCCESS) {
+      if (debug) {
+        printf("thread_info returned 0x%x\n", result);
+      }
+      break;
+    }
+    
+    // if this is the one we're looking for, return the send right
+    if (thread_id == m_ident_info.thread_id)
+    {
+      result_thread = thread_list[i];
+      break;
+    }
+  }
+  
+  vm_size_t thread_list_size = (vm_size_t) (thread_list_count * sizeof (thread_t));
+  vm_deallocate(mach_task_self(), (vm_address_t) thread_list, thread_list_count);
+  
+  return result_thread;
+}
+
+
+/*
+ * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
  * Method:    getThreadIntegerRegisterSet0
- * Signature: (I)[J
+ * Signature: (J)[J
  */
-JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0(JNIEnv *env, jobject this_obj, jint lwp_id) {
+JNIEXPORT jlongArray JNICALL 
+Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0(
+  JNIEnv *env, jobject this_obj, 
+  jlong thread_id) 
+{
   if (debug)
     printf("getThreadRegisterSet0 called\n");
 
@@ -219,8 +290,9 @@
   int i;
   jlongArray registerArray;
   jlong *primitiveArray;
+  task_t gTask = getTask(env, this_obj);
 
-  tid = lwp_id;
+  tid = lookupThreadFromThreadId(gTask, thread_id);
 
   result = thread_get_state(tid, HSDB_THREAD_STATE, (thread_state_t)&state, &count);
 
@@ -321,19 +393,21 @@
 }
 
 /*
- * Class:     sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal
+ * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
  * Method:    translateTID0
  * Signature: (I)I
  */
 JNIEXPORT jint JNICALL
-Java_sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal_translateTID0(JNIEnv *env, jobject this_obj, jint tid) {
+Java_sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal_translateTID0(
+  JNIEnv *env, jobject this_obj, jint tid) 
+{
   if (debug)
     printf("translateTID0 called on tid = 0x%x\n", (int)tid);
 
   kern_return_t result;
   thread_t foreign_tid, usable_tid;
   mach_msg_type_name_t type;
-    
+  
   foreign_tid = tid;
     
   task_t gTask = getTask(env, this_obj);
@@ -421,7 +495,10 @@
  * Method:    attach0
  * Signature: (I)V
  */
-JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I(JNIEnv *env, jobject this_obj, jint jpid) {
+JNIEXPORT void JNICALL 
+Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I(
+  JNIEnv *env, jobject this_obj, jint jpid) 
+{
 JNF_COCOA_ENTER(env);
   if (getenv("JAVA_SAPROC_DEBUG") != NULL)
     debug = JNI_TRUE;
@@ -469,7 +546,10 @@
  * Method:    detach0
  * Signature: ()V
  */
-JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0(JNIEnv *env, jobject this_obj) {
+JNIEXPORT void JNICALL 
+Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0(
+  JNIEnv *env, jobject this_obj) 
+{
 JNF_COCOA_ENTER(env);
   if (debug) printf("detach0 called\n");
 
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebugger.java	Wed Apr 17 12:13:28 2013 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebugger.java	Thu Apr 18 13:42:00 2013 -0700
@@ -48,7 +48,7 @@
   public BsdAddress readCompOopAddress(long address) throws DebuggerException;
   public BsdOopHandle readOopHandle(long address) throws DebuggerException;
   public BsdOopHandle readCompOopHandle(long address) throws DebuggerException;
-  public long[]       getThreadIntegerRegisterSet(int lwp_id) throws DebuggerException;
+  public long[]       getThreadIntegerRegisterSet(long unique_thread_id) throws DebuggerException;
   public long         getAddressValue(Address addr) throws DebuggerException;
   public Address      newAddress(long value) throws DebuggerException;
 
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java	Wed Apr 17 12:13:28 2013 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java	Thu Apr 18 13:42:00 2013 -0700
@@ -90,7 +90,7 @@
                                 throws DebuggerException;
     private native ClosestSymbol lookupByAddress0(long address)
                                 throws DebuggerException;
-    private native long[] getThreadIntegerRegisterSet0(int lwp_id)
+    private native long[] getThreadIntegerRegisterSet0(long unique_thread_id)
                                 throws DebuggerException;
     private native byte[] readBytesFromProcess0(long address, long numBytes)
                                 throws DebuggerException;
@@ -400,10 +400,15 @@
     //
 
     /** From the ThreadAccess interface via Debugger and JVMDebugger */
+    public ThreadProxy getThreadForIdentifierAddress(Address threadIdAddr, Address uniqueThreadIdAddr) {
+        return new BsdThread(this, threadIdAddr, uniqueThreadIdAddr);
+    }
+    @Override
     public ThreadProxy getThreadForIdentifierAddress(Address addr) {
-        return new BsdThread(this, addr);
+        throw new RuntimeException("unimplemented");
     }
 
+
     /** From the ThreadAccess interface via Debugger and JVMDebugger */
     public ThreadProxy getThreadForThreadId(long id) {
         return new BsdThread(this, id);
@@ -449,22 +454,22 @@
     // Thread context access
     //
 
-    public synchronized long[] getThreadIntegerRegisterSet(int lwp_id)
+    public synchronized long[] getThreadIntegerRegisterSet(long unique_thread_id)
                                             throws DebuggerException {
         requireAttach();
         if (isCore) {
-            return getThreadIntegerRegisterSet0(lwp_id);
+            return getThreadIntegerRegisterSet0(unique_thread_id);
         } else {
             class GetThreadIntegerRegisterSetTask implements WorkerThreadTask {
-                int lwp_id;
+                long unique_thread_id;
                 long[] result;
                 public void doit(BsdDebuggerLocal debugger) {
-                    result = debugger.getThreadIntegerRegisterSet0(lwp_id);
+                    result = debugger.getThreadIntegerRegisterSet0(unique_thread_id);
                 }
             }
 
             GetThreadIntegerRegisterSetTask task = new GetThreadIntegerRegisterSetTask();
-            task.lwp_id = lwp_id;
+            task.unique_thread_id = unique_thread_id;
             workerThread.execute(task);
             return task.result;
         }
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java	Wed Apr 17 12:13:28 2013 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java	Thu Apr 18 13:42:00 2013 -0700
@@ -28,21 +28,23 @@
 
 class BsdThread implements ThreadProxy {
     private BsdDebugger debugger;
-    private int           lwp_id;
+    private int         thread_id;
+    private long        unique_thread_id;
 
     /** The address argument must be the address of the _thread_id in the
         OSThread. It's value is result ::gettid() call. */
-    BsdThread(BsdDebugger debugger, Address addr) {
+    BsdThread(BsdDebugger debugger, Address threadIdAddr, Address uniqueThreadIdAddr) {
         this.debugger = debugger;
         // FIXME: size of data fetched here should be configurable.
         // However, making it so would produce a dependency on the "types"
         // package from the debugger package, which is not desired.
-        this.lwp_id = (int) addr.getCIntegerAt(0, 4, true);
+        this.thread_id = (int) threadIdAddr.getCIntegerAt(0, 4, true);
+        this.unique_thread_id = uniqueThreadIdAddr.getCIntegerAt(0, 8, true);
     }
 
     BsdThread(BsdDebugger debugger, long id) {
         this.debugger = debugger;
-        this.lwp_id = (int) id;
+        this.thread_id = (int) id;
     }
 
     public boolean equals(Object obj) {
@@ -50,19 +52,19 @@
             return false;
         }
 
-        return (((BsdThread) obj).lwp_id == lwp_id);
+        return (((BsdThread) obj).thread_id == thread_id);
     }
 
     public int hashCode() {
-        return lwp_id;
+        return thread_id;
     }
 
     public String toString() {
-        return Integer.toString(lwp_id);
+        return Integer.toString(thread_id);
     }
 
     public ThreadContext getContext() throws IllegalThreadStateException {
-        long[] data = debugger.getThreadIntegerRegisterSet(lwp_id);
+        long[] data = debugger.getThreadIntegerRegisterSet(unique_thread_id);
         ThreadContext context = BsdThreadContextFactory.createThreadContext(debugger);
         for (int i = 0; i < data.length; i++) {
             context.setRegister(i, data[i]);
--- a/agent/src/share/classes/sun/jvm/hotspot/runtime/bsd_amd64/BsdAMD64JavaThreadPDAccess.java	Wed Apr 17 12:13:28 2013 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/bsd_amd64/BsdAMD64JavaThreadPDAccess.java	Thu Apr 18 13:42:00 2013 -0700
@@ -28,6 +28,8 @@
 import java.util.*;
 import sun.jvm.hotspot.debugger.*;
 import sun.jvm.hotspot.debugger.amd64.*;
+import sun.jvm.hotspot.debugger.bsd.BsdDebugger;
+import sun.jvm.hotspot.debugger.bsd.BsdDebuggerLocal;
 import sun.jvm.hotspot.runtime.*;
 import sun.jvm.hotspot.runtime.amd64.*;
 import sun.jvm.hotspot.runtime.x86.*;
@@ -38,8 +40,9 @@
   private static AddressField  lastJavaFPField;
   private static AddressField  osThreadField;
 
-  // Field from OSThread
+  // Fields from OSThread
   private static CIntegerField osThreadThreadIDField;
+  private static CIntegerField osThreadUniqueThreadIDField;
 
   // This is currently unneeded but is being kept in case we change
   // the currentFrameGuess algorithm
@@ -61,7 +64,8 @@
     lastJavaFPField         = anchorType.getAddressField("_last_Java_fp");
 
     Type osThreadType = db.lookupType("OSThread");
-    osThreadThreadIDField   = osThreadType.getCIntegerField("_thread_id");
+    osThreadThreadIDField = osThreadType.getCIntegerField("_thread_id");
+    osThreadUniqueThreadIDField = osThreadType.getCIntegerField("_unique_thread_id");
   }
 
   public    Address getLastJavaFP(Address addr) {
@@ -125,8 +129,9 @@
     Address osThreadAddr = osThreadField.getValue(addr);
     // Get the address of the _thread_id from the OSThread
     Address threadIdAddr = osThreadAddr.addOffsetTo(osThreadThreadIDField.getOffset());
+    Address uniqueThreadIdAddr = osThreadAddr.addOffsetTo(osThreadUniqueThreadIDField.getOffset());
 
-    JVMDebugger debugger = VM.getVM().getDebugger();
-    return debugger.getThreadForIdentifierAddress(threadIdAddr);
+    BsdDebuggerLocal debugger = (BsdDebuggerLocal) VM.getVM().getDebugger();
+    return debugger.getThreadForIdentifierAddress(threadIdAddr, uniqueThreadIdAddr);
   }
 }
--- a/make/hotspot_version	Wed Apr 17 12:13:28 2013 -0700
+++ b/make/hotspot_version	Thu Apr 18 13:42:00 2013 -0700
@@ -35,7 +35,7 @@
 
 HS_MAJOR_VER=24
 HS_MINOR_VER=0
-HS_BUILD_NUMBER=40
+HS_BUILD_NUMBER=41
 
 JDK_MAJOR_VER=1
 JDK_MINOR_VER=7
--- a/make/solaris/makefiles/vm.make	Wed Apr 17 12:13:28 2013 -0700
+++ b/make/solaris/makefiles/vm.make	Thu Apr 18 13:42:00 2013 -0700
@@ -135,9 +135,7 @@
 LIBS += -lsocket -lsched -ldl $(LIBM) -lthread -lc -ldemangle
 endif # sparcWorks
 
-ifeq ("${Platform_arch}", "sparc")
 LIBS += -lkstat
-endif
 
 # By default, link the *.o into the library, not the executable.
 LINK_INTO$(LINK_INTO) = LIBJVM
--- a/src/os/bsd/vm/osThread_bsd.hpp	Wed Apr 17 12:13:28 2013 -0700
+++ b/src/os/bsd/vm/osThread_bsd.hpp	Thu Apr 18 13:42:00 2013 -0700
@@ -55,6 +55,11 @@
   // (e.g. pthread_kill).
   pthread_t _pthread_id;
 
+  // This is the "thread_id" from struct thread_identifier_info. According to a
+  // comment in thread_info.h, this is a "system-wide unique 64-bit thread id".
+  // The value is used by SA to correlate threads.
+  uint64_t _unique_thread_id;
+
   sigset_t _caller_sigmask; // Caller's signal mask
 
  public:
@@ -83,6 +88,10 @@
     _pthread_id = tid;
   }
 
+  void set_unique_thread_id(uint64_t id) {
+    _unique_thread_id = id;
+  }
+
   // ***************************************************************
   // suspension support.
   // ***************************************************************
--- a/src/os/bsd/vm/os_bsd.cpp	Wed Apr 17 12:13:28 2013 -0700
+++ b/src/os/bsd/vm/os_bsd.cpp	Thu Apr 18 13:42:00 2013 -0700
@@ -970,6 +970,18 @@
 objc_registerThreadWithCollector_t objc_registerThreadWithCollectorFunction = NULL;
 #endif
 
+#ifdef __APPLE__
+static uint64_t locate_unique_thread_id() {
+  // Additional thread_id used to correlate threads in SA
+  thread_identifier_info_data_t     m_ident_info;
+  mach_msg_type_number_t            count = THREAD_IDENTIFIER_INFO_COUNT;
+
+  thread_info(::mach_thread_self(), THREAD_IDENTIFIER_INFO,
+              (thread_info_t) &m_ident_info, &count);
+  return m_ident_info.thread_id;
+}
+#endif
+
 // Thread start routine for all newly created threads
 static void *java_start(Thread *thread) {
   // Try to randomize the cache line index of hot stack frames.
@@ -999,6 +1011,7 @@
 #ifdef __APPLE__
   // thread_id is mach thread on macos
   osthread->set_thread_id(::mach_thread_self());
+  osthread->set_unique_thread_id(locate_unique_thread_id());
 #else
   // thread_id is pthread_id on BSD
   osthread->set_thread_id(::pthread_self());
@@ -1195,6 +1208,7 @@
 #ifdef _ALLBSD_SOURCE
 #ifdef __APPLE__
   osthread->set_thread_id(::mach_thread_self());
+  osthread->set_unique_thread_id(locate_unique_thread_id());
 #else
   osthread->set_thread_id(::pthread_self());
 #endif
--- a/src/os_cpu/bsd_x86/vm/vmStructs_bsd_x86.hpp	Wed Apr 17 12:13:28 2013 -0700
+++ b/src/os_cpu/bsd_x86/vm/vmStructs_bsd_x86.hpp	Thu Apr 18 13:42:00 2013 -0700
@@ -35,7 +35,7 @@
   /* Threads (NOTE: incomplete) */                                                                                                   \
   /******************************/                                                                                                   \
   nonstatic_field(OSThread,                      _thread_id,                                      OSThread::thread_id_t)             \
-  nonstatic_field(OSThread,                      _pthread_id,                                     pthread_t)                         \
+  nonstatic_field(OSThread,                      _unique_thread_id,                               uint64_t)                          \
   /* This must be the last entry, and must be present */                                                                             \
   last_entry()
 
@@ -43,11 +43,10 @@
 #define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type, last_entry) \
                                                                           \
   /**********************/                                                \
-  /* Posix Thread IDs   */                                                \
+  /* Thread IDs         */                                                \
   /**********************/                                                \
                                                                           \
   declare_unsigned_integer_type(OSThread::thread_id_t)                    \
-  declare_unsigned_integer_type(pthread_t)                                \
                                                                           \
   /* This must be the last entry, and must be present */                  \
   last_entry()
--- a/src/share/vm/classfile/systemDictionary.cpp	Wed Apr 17 12:13:28 2013 -0700
+++ b/src/share/vm/classfile/systemDictionary.cpp	Thu Apr 18 13:42:00 2013 -0700
@@ -54,7 +54,11 @@
 #include "runtime/signature.hpp"
 #include "services/classLoadingService.hpp"
 #include "services/threadService.hpp"
-#include "trace/traceMacros.hpp"
+
+#if INCLUDE_TRACE
+ #include "memory/iterator.hpp"
+ #include "trace/tracing.hpp"
+#endif
 
 
 Dictionary*            SystemDictionary::_dictionary          = NULL;
@@ -581,6 +585,8 @@
   assert(name != NULL && !FieldType::is_array(name) &&
          !FieldType::is_obj(name), "invalid class name");
 
+  TracingTime class_load_start_time = Tracing::time();
+
   // UseNewReflection
   // Fix for 4474172; see evaluation for more details
   class_loader = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader()));
@@ -820,6 +826,7 @@
         }
         return NULL;
       }
+      post_class_load_event(class_load_start_time, k, class_loader);
     }
   }
 
@@ -939,6 +946,8 @@
                                         TRAPS) {
   TempNewSymbol parsed_name = NULL;
 
+  TracingTime class_load_start_time = Tracing::time();
+
   // Parse the stream. Note that we do this even though this klass might
   // already be present in the SystemDictionary, otherwise we would not
   // throw potential ClassFormatErrors.
@@ -996,6 +1005,8 @@
         assert(THREAD->is_Java_thread(), "thread->is_Java_thread()");
         JvmtiExport::post_class_load((JavaThread *) THREAD, k());
     }
+
+    post_class_load_event(class_load_start_time, k, class_loader);
   }
 
   return k();
@@ -1012,7 +1023,6 @@
                                                ClassFileStream* st,
                                                bool verify,
                                                TRAPS) {
-
   // Classloaders that support parallelism, e.g. bootstrap classloader,
   // or all classloaders with UnsyncloadClass do not acquire lock here
   bool DoObjectLock = true;
@@ -1655,6 +1665,7 @@
   return newsize;
 }
 bool SystemDictionary::do_unloading(BoolObjectClosure* is_alive) {
+  post_class_unload_events(is_alive);
   bool result = dictionary()->do_unloading(is_alive);
   constraints()->purge_loader_constraints(is_alive);
   resolution_errors()->purge_resolution_errors(is_alive);
@@ -2601,6 +2612,73 @@
             "Loaded klasses should be in SystemDictionary");
 }
 
+// utility function for posting class load event
+void SystemDictionary::post_class_load_event(TracingTime start_time,
+                                             instanceKlassHandle k,
+                                             Handle initiating_loader) {
+#if INCLUDE_TRACE
+  EventClassLoad event(UNTIMED);
+  if (event.should_commit()) {
+    event.set_endtime(Tracing::time());
+    event.set_starttime(start_time);
+    event.set_loadedClass(k());
+    oop defining_class_loader = k->class_loader();
+    event.set_definingClassLoader(defining_class_loader != NULL ?
+                                  defining_class_loader->klass() : (klassOop)NULL);
+    oop class_loader = initiating_loader.is_null() ? (oop)NULL : initiating_loader();
+    event.set_initiatingClassLoader(class_loader != NULL ?
+                                    class_loader->klass() : (klassOop)NULL);
+    event.commit();
+  }
+#endif /* INCLUDE_TRACE */
+}
+
+void SystemDictionary::post_class_unload_events(BoolObjectClosure* is_alive) {
+#if INCLUDE_TRACE
+  assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
+  if (Tracing::enabled()) {
+    _should_write_unload_events = Tracing::is_event_enabled(TraceClassUnloadEvent);
+    _class_unload_time = Tracing::time();
+    _is_alive = is_alive;
+    classes_do(&class_unload_event);
+
+    if (_no_of_classes_unloading > 0) {
+      Tracing::on_unloading_classes(is_alive, _no_of_classes_unloading);
+      _no_of_classes_unloading = 0;
+    }
+    _should_write_unload_events = false;
+    _is_alive = NULL;
+  }
+#endif /* INCLUDE_TRACE */
+}
+
+#if INCLUDE_TRACE
+
+TracingTime SystemDictionary::_class_unload_time;
+BoolObjectClosure* SystemDictionary::_is_alive = NULL;
+int SystemDictionary::_no_of_classes_unloading = 0;
+bool SystemDictionary::_should_write_unload_events = false;
+
+void SystemDictionary::class_unload_event(klassOop curklass) {
+
+  Klass* myklass = curklass->klass_part();
+  oop class_loader = myklass->class_loader();
+
+  if (class_loader != NULL && _is_alive != NULL && !_is_alive->do_object_b(class_loader)) {
+    _no_of_classes_unloading++;
+    if (_should_write_unload_events) {
+      // post class unload event
+      EventClassUnload event(UNTIMED);
+      event.set_endtime(_class_unload_time);
+      event.set_unloadedClass(curklass);
+      event.set_definingClassLoader(class_loader->klass());
+      event.commit();
+    }
+  }
+}
+
+#endif /* INCLUDE_TRACE */
+
 #ifndef PRODUCT
 
 // statistics code
--- a/src/share/vm/classfile/systemDictionary.hpp	Wed Apr 17 12:13:28 2013 -0700
+++ b/src/share/vm/classfile/systemDictionary.hpp	Thu Apr 18 13:42:00 2013 -0700
@@ -33,6 +33,7 @@
 #include "runtime/reflectionUtils.hpp"
 #include "utilities/hashtable.hpp"
 #include "utilities/hashtable.inline.hpp"
+#include "trace/traceTime.hpp"
 
 // The system dictionary stores all loaded classes and maps:
 //
@@ -76,6 +77,7 @@
 template <MEMFLAGS F> class HashtableBucket;
 class ResolutionErrorTable;
 class SymbolPropertyTable;
+class BoolObjectClosure;
 
 // Certain classes are preloaded, such as java.lang.Object and java.lang.String.
 // They are all "well-known", in the sense that no class loader is allowed
@@ -613,6 +615,11 @@
   // Setup link to hierarchy
   static void add_to_hierarchy(instanceKlassHandle k, TRAPS);
 
+  // event based tracing
+  static void post_class_load_event(TracingTime start_time, instanceKlassHandle k,
+                                    Handle initiating_loader);
+  static void post_class_unload_events(BoolObjectClosure* is_alive);
+
 private:
   // We pass in the hashtable index so we can calculate it outside of
   // the SystemDictionary_lock.
@@ -669,6 +676,14 @@
 
   static bool _has_loadClassInternal;
   static bool _has_checkPackageAccess;
+
+#if INCLUDE_TRACE
+  static TracingTime _class_unload_time;
+  static BoolObjectClosure* _is_alive;
+  static int _no_of_classes_unloading;
+  static bool _should_write_unload_events;
+  static void class_unload_event(klassOop curklass);
+#endif
 };
 
 class SystemDictionaryHandles : AllStatic {
--- a/src/share/vm/gc_implementation/g1/concurrentMark.hpp	Wed Apr 17 12:13:28 2013 -0700
+++ b/src/share/vm/gc_implementation/g1/concurrentMark.hpp	Thu Apr 18 13:42:00 2013 -0700
@@ -546,8 +546,6 @@
   void clear_has_overflown()     { _has_overflown = false; }
   bool restart_for_overflow()    { return _restart_for_overflow; }
 
-  bool has_aborted()             { return _has_aborted; }
-
   // Methods to enter the two overflow sync barriers
   void enter_first_sync_barrier(int task_num);
   void enter_second_sync_barrier(int task_num);
@@ -795,6 +793,8 @@
   // Called to abort the marking cycle after a Full GC takes palce.
   void abort();
 
+  bool has_aborted()      { return _has_aborted; }
+
   // This prints the global/local fingers. It is used for debugging.
   NOT_PRODUCT(void print_finger();)
 
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Wed Apr 17 12:13:28 2013 -0700
+++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Thu Apr 18 13:42:00 2013 -0700
@@ -1905,7 +1905,7 @@
   _ref_processor_stw(NULL),
   _process_strong_tasks(new SubTasksDone(G1H_PS_NumElements)),
   _bot_shared(NULL),
-  _evac_failure_scan_stack(NULL) ,
+  _evac_failure_scan_stack(NULL),
   _mark_in_progress(false),
   _cg1r(NULL), _summary_bytes_used(0),
   _g1mm(NULL),
@@ -1949,21 +1949,19 @@
   int n_rem_sets = HeapRegionRemSet::num_par_rem_sets();
   assert(n_rem_sets > 0, "Invariant.");
 
-  HeapRegionRemSetIterator** iter_arr =
-    NEW_C_HEAP_ARRAY(HeapRegionRemSetIterator*, n_queues, mtGC);
-  for (int i = 0; i < n_queues; i++) {
-    iter_arr[i] = new HeapRegionRemSetIterator();
-  }
-  _rem_set_iterator = iter_arr;
-
+  HeapRegionRemSetIterator** iter_arr = NEW_C_HEAP_ARRAY(HeapRegionRemSetIterator*, n_queues, mtGC);
   _worker_cset_start_region = NEW_C_HEAP_ARRAY(HeapRegion*, n_queues, mtGC);
   _worker_cset_start_region_time_stamp = NEW_C_HEAP_ARRAY(unsigned int, n_queues, mtGC);
+  _evacuation_failed_info_array = NEW_C_HEAP_ARRAY(EvacuationFailedInfo, n_queues, mtGC);
 
   for (int i = 0; i < n_queues; i++) {
     RefToScanQueue* q = new RefToScanQueue();
     q->initialize();
     _task_queues->register_queue(i, q);
-  }
+    iter_arr[i] = new HeapRegionRemSetIterator();
+    ::new (&_evacuation_failed_info_array[i]) EvacuationFailedInfo();
+  }
+  _rem_set_iterator = iter_arr;
 
   clear_cset_start_regions();
 
@@ -2518,6 +2516,9 @@
   if (_concurrent_cycle_started) {
     _gc_timer_cm->register_gc_end(os::elapsed_counter());
 
+    if (_cm->has_aborted()) {
+      _gc_tracer_cm->report_concurrent_mode_failure();
+    }
     _gc_tracer_cm->report_gc_end(_gc_timer_cm->gc_end(), _gc_timer_cm->time_partitions());
 
     _concurrent_cycle_started = false;
@@ -4035,13 +4036,19 @@
 #endif // YOUNG_LIST_VERBOSE
 
         g1_policy()->record_survivor_regions(_young_list->survivor_length(),
-                                            _young_list->first_survivor_region(),
-                                            _young_list->last_survivor_region());
+                                             _young_list->first_survivor_region(),
+                                             _young_list->last_survivor_region());
 
         _young_list->reset_auxilary_lists();
 
         if (evacuation_failed()) {
           _summary_bytes_used = recalculate_used();
+          uint n_queues = MAX2((int)ParallelGCThreads, 1);
+          for (uint i = 0; i < n_queues; i++) {
+            if (_evacuation_failed_info_array[i].has_failed()) {
+              _gc_tracer_stw->report_evacuation_failed(_evacuation_failed_info_array[i]);
+            }
+          }
         } else {
           // The "used" of the the collection set have already been subtracted
           // when they were freed.  Add in the bytes evacuated.
@@ -4355,7 +4362,7 @@
 }
 
 oop
-G1CollectedHeap::handle_evacuation_failure_par(OopsInHeapRegionClosure* cl,
+G1CollectedHeap::handle_evacuation_failure_par(G1ParScanThreadState* _par_scan_state,
                                                oop old) {
   assert(obj_in_cs(old),
          err_msg("obj: "PTR_FORMAT" should still be in the CSet",
@@ -4364,7 +4371,12 @@
   oop forward_ptr = old->forward_to_atomic(old);
   if (forward_ptr == NULL) {
     // Forward-to-self succeeded.
-
+    assert(_par_scan_state != NULL, "par scan state");
+    OopsInHeapRegionClosure* cl = _par_scan_state->evac_failure_closure();
+    uint queue_num = _par_scan_state->queue_num();
+
+    _evacuation_failed = true;
+    _evacuation_failed_info_array[queue_num].register_copy_failure(old->size());
     if (_evac_failure_closure != cl) {
       MutexLockerEx x(EvacFailureStack_lock, Mutex::_no_safepoint_check_flag);
       assert(!_drain_in_progress,
@@ -4395,8 +4407,6 @@
 }
 
 void G1CollectedHeap::handle_evacuation_failure_common(oop old, markOop m) {
-  set_evacuation_failed(true);
-
   preserve_mark_if_necessary(old, m);
 
   HeapRegion* r = heap_region_containing(old);
@@ -4646,8 +4656,7 @@
   if (obj_ptr == NULL) {
     // This will either forward-to-self, or detect that someone else has
     // installed a forwarding pointer.
-    OopsInHeapRegionClosure* cl = _par_scan_state->evac_failure_closure();
-    return _g1->handle_evacuation_failure_par(cl, old);
+    return _g1->handle_evacuation_failure_par(_par_scan_state, old);
   }
 
   oop obj = oop(obj_ptr);
@@ -5660,7 +5669,7 @@
 
 void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) {
   _expand_heap_after_alloc_failure = true;
-  set_evacuation_failed(false);
+  _evacuation_failed = false;
 
   // Should G1EvacuationFailureALot be in effect for this GC?
   NOT_PRODUCT(set_evacuation_failure_alot_for_current_gc();)
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp	Wed Apr 17 12:13:28 2013 -0700
+++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp	Thu Apr 18 13:42:00 2013 -0700
@@ -68,6 +68,7 @@
 class STWGCTimer;
 class G1NewTracer;
 class G1OldTracer;
+class EvacuationFailedInfo;
 
 typedef OverflowTaskQueue<StarTask, mtGC>         RefToScanQueue;
 typedef GenericTaskQueueSet<RefToScanQueue, mtGC> RefToScanQueueSet;
@@ -166,7 +167,7 @@
 // An instance is embedded into the G1CH and used as the
 // (optional) _is_alive_non_header closure in the STW
 // reference processor. It is also extensively used during
-// refence processing during STW evacuation pauses.
+// reference processing during STW evacuation pauses.
 class G1STWIsAliveClosure: public BoolObjectClosure {
   G1CollectedHeap* _g1;
 public:
@@ -885,9 +886,7 @@
   // True iff a evacuation has failed in the current collection.
   bool _evacuation_failed;
 
-  // Set the attribute indicating whether evacuation has failed in the
-  // current collection.
-  void set_evacuation_failed(bool b) { _evacuation_failed = b; }
+  EvacuationFailedInfo* _evacuation_failed_info_array;
 
   // Failed evacuations cause some logical from-space objects to have
   // forwarding pointers to themselves.  Reset them.
@@ -929,7 +928,7 @@
   void finalize_for_evac_failure();
 
   // An attempt to evacuate "obj" has failed; take necessary steps.
-  oop handle_evacuation_failure_par(OopsInHeapRegionClosure* cl, oop obj);
+  oop handle_evacuation_failure_par(G1ParScanThreadState* _par_scan_state, oop obj);
   void handle_evacuation_failure_common(oop obj, markOop m);
 
 #ifndef PRODUCT
@@ -961,13 +960,13 @@
   inline bool evacuation_should_fail();
 
   // Reset the G1EvacuationFailureALot counters.  Should be called at
-  // the end of an evacuation pause in which an evacuation failure ocurred.
+  // the end of an evacuation pause in which an evacuation failure occurred.
   inline void reset_evacuation_should_fail();
 #endif // !PRODUCT
 
   // ("Weak") Reference processing support.
   //
-  // G1 has 2 instances of the referece processor class. One
+  // G1 has 2 instances of the reference processor class. One
   // (_ref_processor_cm) handles reference object discovery
   // and subsequent processing during concurrent marking cycles.
   //
@@ -1238,7 +1237,7 @@
 
   // verify_region_sets_optional() is planted in the code for
   // list verification in non-product builds (and it can be enabled in
-  // product builds by definning HEAP_REGION_SET_FORCE_VERIFY to be 1).
+  // product builds by defining HEAP_REGION_SET_FORCE_VERIFY to be 1).
 #if HEAP_REGION_SET_FORCE_VERIFY
   void verify_region_sets_optional() {
     verify_region_sets();
@@ -1310,7 +1309,7 @@
   // the context of the vm thread.
   virtual void collect_as_vm_thread(GCCause::Cause cause);
 
-  // True iff a evacuation has failed in the most-recent collection.
+  // True iff an evacuation has failed in the most-recent collection.
   bool evacuation_failed() { return _evacuation_failed; }
 
   // It will free a region if it has allocated objects in it that are
@@ -1816,7 +1815,7 @@
   G1ParScanHeapEvacClosure*     _evac_cl;
   G1ParScanPartialArrayClosure* _partial_scan_cl;
 
-  int _hash_seed;
+  int  _hash_seed;
   uint _queue_num;
 
   size_t _term_attempts;
@@ -2020,7 +2019,6 @@
     }
   }
 
-public:
   void trim_queue();
 };
 
--- a/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp	Wed Apr 17 12:13:28 2013 -0700
+++ b/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp	Thu Apr 18 13:42:00 2013 -0700
@@ -36,7 +36,7 @@
   bool        _print_sum;
 
   // We are caching the sum and average to only have to calculate them once.
-  // This is not done in an MT-safe way. It is intetened to allow single
+  // This is not done in an MT-safe way. It is intended to allow single
   // threaded code to call sum() and average() multiple times in any order
   // without having to worry about the cost.
   bool   _has_new_data;
@@ -135,7 +135,7 @@
   double _min_clear_cc_time_ms;         // min
   double _max_clear_cc_time_ms;         // max
   double _cur_clear_cc_time_ms;         // clearing time during current pause
-  double _cum_clear_cc_time_ms;         // cummulative clearing time
+  double _cum_clear_cc_time_ms;         // cumulative clearing time
   jlong  _num_cc_clears;                // number of times the card count cache has been cleared
 
   double _cur_collection_start_sec;
--- a/src/share/vm/gc_implementation/shared/copyFailedInfo.hpp	Wed Apr 17 12:13:28 2013 -0700
+++ b/src/share/vm/gc_implementation/shared/copyFailedInfo.hpp	Thu Apr 18 13:42:00 2013 -0700
@@ -28,35 +28,31 @@
 #include "runtime/thread.hpp"
 #include "utilities/globalDefinitions.hpp"
 
-class CopyFailedInfo VALUE_OBJ_CLASS_SPEC {
+class CopyFailedInfo : public CHeapObj<mtGC> {
   size_t    _first_size;
   size_t    _smallest_size;
   size_t    _total_size;
   uint      _count;
-  OSThread* _thread;
 
  public:
-  CopyFailedInfo() : _first_size(0), _smallest_size(0), _total_size(0), _count(0), _thread(NULL) {}
+  CopyFailedInfo() : _first_size(0), _smallest_size(0), _total_size(0), _count(0) {}
 
-  void register_copy_failure(size_t size) {
+  virtual void register_copy_failure(size_t size) {
     if (_first_size == 0) {
       _first_size = size;
       _smallest_size = size;
-      _thread = Thread::current()->osthread();
     } else if (size < _smallest_size) {
       _smallest_size = size;
     }
     _total_size += size;
     _count++;
-    assert(_thread == Thread::current()->osthread(), "The PromotionFailedInfo should be thread local.");
   }
 
-  void reset() {
+  virtual void reset() {
     _first_size = 0;
     _smallest_size = 0;
     _total_size = 0;
     _count = 0;
-    _thread = NULL;
   }
 
   bool has_failed() const { return _count != 0; }
@@ -64,9 +60,31 @@
   size_t smallest_size() const { return _smallest_size; }
   size_t total_size() const { return _total_size; }
   uint failed_count() const { return _count; }
+};
+
+class PromotionFailedInfo : public CopyFailedInfo {
+  OSThread* _thread;
+
+ public:
+  PromotionFailedInfo() : CopyFailedInfo(), _thread(NULL) {}
+
+  void register_copy_failure(size_t size) {
+    CopyFailedInfo::register_copy_failure(size);
+    if (_thread == NULL) {
+      _thread = Thread::current()->osthread();
+    } else {
+      assert(_thread == Thread::current()->osthread(), "The PromotionFailedInfo should be thread local.");
+    }
+  }
+
+  void reset() {
+    CopyFailedInfo::reset();
+    _thread = NULL;
+  }
+
   OSThread* thread() const { return _thread; }
 };
 
-class PromotionFailedInfo : public CopyFailedInfo {};
+class EvacuationFailedInfo : public CopyFailedInfo {};
 
 #endif /* SHARE_VM_GC_IMPLEMENTATION_SHARED_COPYFAILEDINFO_HPP */
--- a/src/share/vm/gc_implementation/shared/gcTrace.cpp	Wed Apr 17 12:13:28 2013 -0700
+++ b/src/share/vm/gc_implementation/shared/gcTrace.cpp	Thu Apr 18 13:42:00 2013 -0700
@@ -161,7 +161,7 @@
   _parallel_old_gc_info.report_dense_prefix(dense_prefix);
 }
 
-void CMSTracer::report_concurrent_mode_failure() {
+void OldGCTracer::report_concurrent_mode_failure() {
   assert_set_gc_id();
 
   send_concurrent_mode_failure_event();
@@ -186,4 +186,11 @@
 
   send_evacuation_info_event(info);
 }
+
+void G1NewTracer::report_evacuation_failed(EvacuationFailedInfo& ef_info) {
+  assert_set_gc_id();
+
+  send_evacuation_failed_event(ef_info);
+  ef_info.reset();
+}
 #endif
--- a/src/share/vm/gc_implementation/shared/gcTrace.hpp	Wed Apr 17 12:13:28 2013 -0700
+++ b/src/share/vm/gc_implementation/shared/gcTrace.hpp	Thu Apr 18 13:42:00 2013 -0700
@@ -162,8 +162,12 @@
   OldGCTracer(GCName name) : GCTracer(name) {}
   virtual void report_gc_end_impl(jlong timestamp, TimePartitions* time_partitions);
 
+ public:
+  void report_concurrent_mode_failure();
+
  private:
   void send_old_gc_event() const;
+  void send_concurrent_mode_failure_event();
 };
 
 class ParallelOldTracer : public OldGCTracer {
@@ -210,21 +214,18 @@
   void report_yc_type(G1YCType type);
   void report_gc_end_impl(jlong timestamp, TimePartitions* time_partitions);
   void report_evacuation_info(EvacuationInfo* info);
+  void report_evacuation_failed(EvacuationFailedInfo& ef_info);
 
  private:
   void send_g1_young_gc_event();
   void send_evacuation_info_event(EvacuationInfo* info);
+  void send_evacuation_failed_event(const EvacuationFailedInfo& ef_info) const;
 };
 #endif
 
 class CMSTracer : public OldGCTracer {
  public:
   CMSTracer() : OldGCTracer(ConcurrentMarkSweep) {}
-
-  void report_concurrent_mode_failure();
-
- private:
-  void send_concurrent_mode_failure_event();
 };
 
 class G1OldTracer : public OldGCTracer {
--- a/src/share/vm/gc_implementation/shared/gcTraceSend.cpp	Wed Apr 17 12:13:28 2013 -0700
+++ b/src/share/vm/gc_implementation/shared/gcTraceSend.cpp	Thu Apr 18 13:42:00 2013 -0700
@@ -101,7 +101,6 @@
   failed_info.set_firstSize(cf_info.first_size());
   failed_info.set_smallestSize(cf_info.smallest_size());
   failed_info.set_totalSize(cf_info.total_size());
-  failed_info.set_thread(cf_info.thread()->thread_id());
   return failed_info;
 }
 
@@ -110,11 +109,13 @@
   if (e.should_commit()) {
     e.set_gcId(_shared_gc_info.id());
     e.set_data(to_trace_struct(pf_info));
+    e.set_thread(pf_info.thread()->thread_id());
     e.commit();
   }
 }
 
-void CMSTracer::send_concurrent_mode_failure_event() {
+// Common to CMS and G1
+void OldGCTracer::send_concurrent_mode_failure_event() {
   EventConcurrentModeFailure e;
   if (e.should_commit()) {
     e.set_gcId(_shared_gc_info.id());
@@ -135,7 +136,7 @@
 
 bool GCTracer::should_send_object_count_after_gc_event() const {
 #if INCLUDE_TRACE
-  return Tracing::enabled(EventObjectCountAfterGC::eventId);
+  return Tracing::is_event_enabled(EventObjectCountAfterGC::eventId);
 #else
   return false;
 #endif
@@ -168,6 +169,15 @@
     e.commit();
   }
 }
+
+void G1NewTracer::send_evacuation_failed_event(const EvacuationFailedInfo& ef_info) const {
+  EventEvacuationFailed e;
+  if (e.should_commit()) {
+    e.set_gcId(_shared_gc_info.id());
+    e.set_data(to_trace_struct(ef_info));
+    e.commit();
+  }
+}
 #endif
 
 static TraceStructVirtualSpace to_trace_struct(const VirtualSpaceSummary& summary) {
--- a/src/share/vm/gc_implementation/shared/vmGCOperations.cpp	Wed Apr 17 12:13:28 2013 -0700
+++ b/src/share/vm/gc_implementation/shared/vmGCOperations.cpp	Thu Apr 18 13:42:00 2013 -0700
@@ -145,19 +145,18 @@
 }
 
 bool VM_GC_HeapInspection::collect() {
-  CollectedHeap* ch = Universe::heap();
-  ch->ensure_parsability(false); // must happen, even if collection does
-                                 // not happen (e.g. due to GC_locker)
-
   if (GC_locker::is_active()) {
     return false;
   }
-  ch->collect_as_vm_thread(GCCause::_heap_inspection);
+  Universe::heap()->collect_as_vm_thread(GCCause::_heap_inspection);
   return true;
 }
 
 void VM_GC_HeapInspection::doit() {
   HandleMark hm;
+  Universe::heap()->ensure_parsability(false); // must happen, even if collection does
+                                               // not happen (e.g. due to GC_locker)
+                                               // or _full_gc being false
   if (_full_gc) {
     if (!collect()) {
       // The collection attempt was skipped because the gc locker is held.
--- a/src/share/vm/runtime/objectMonitor.cpp	Wed Apr 17 12:13:28 2013 -0700
+++ b/src/share/vm/runtime/objectMonitor.cpp	Thu Apr 18 13:42:00 2013 -0700
@@ -973,7 +973,7 @@
 #if INCLUDE_TRACE
    // get the owner's thread id for the MonitorEnter event
    // if it is enabled and the thread isn't suspended
-   if (not_suspended && Tracing::enabled(TraceJavaMonitorEnterEvent)) {
+   if (not_suspended && Tracing::is_event_enabled(TraceJavaMonitorEnterEvent)) {
      _previous_owner_tid = SharedRuntime::get_java_tid(Self);
    }
 #endif
--- a/src/share/vm/runtime/thread.hpp	Wed Apr 17 12:13:28 2013 -0700
+++ b/src/share/vm/runtime/thread.hpp	Thu Apr 18 13:42:00 2013 -0700
@@ -1042,11 +1042,11 @@
 
   // native memory tracking
   inline MemRecorder* get_recorder() const          { return (MemRecorder*)_recorder; }
-  inline void         set_recorder(MemRecorder* rc) { _recorder = (volatile MemRecorder*)rc; }
+  inline void         set_recorder(MemRecorder* rc) { _recorder = rc; }
 
  private:
   // per-thread memory recorder
-  volatile MemRecorder* _recorder;
+  MemRecorder* volatile _recorder;
 
   // Suspend/resume support for JavaThread
  private:
--- a/src/share/vm/services/memTrackWorker.cpp	Wed Apr 17 12:13:28 2013 -0700
+++ b/src/share/vm/services/memTrackWorker.cpp	Thu Apr 18 13:42:00 2013 -0700
@@ -39,7 +39,7 @@
   }
 }
 
-MemTrackWorker::MemTrackWorker() {
+MemTrackWorker::MemTrackWorker(MemSnapshot* snapshot): _snapshot(snapshot) {
   // create thread uses cgc thread type for now. We should revisit
   // the option, or create new thread type.
   _has_error = !os::create_thread(this, os::cgc_thread);
@@ -88,8 +88,7 @@
   assert(MemTracker::is_on(), "native memory tracking is off");
   this->initialize_thread_local_storage();
   this->record_stack_base_and_size();
-  MemSnapshot* snapshot = MemTracker::get_snapshot();
-  assert(snapshot != NULL, "Worker should not be started");
+  assert(_snapshot != NULL, "Worker should not be started");
   MemRecorder* rec;
   unsigned long processing_generation = 0;
   bool          worker_idle = false;
@@ -109,7 +108,7 @@
       }
 
       // merge the recorder into staging area
-      if (!snapshot->merge(rec)) {
+      if (!_snapshot->merge(rec)) {
         MemTracker::shutdown(MemTracker::NMT_out_of_memory);
       } else {
         NOT_PRODUCT(_merge_count ++;)
@@ -132,7 +131,7 @@
           _head = (_head + 1) % MAX_GENERATIONS;
         }
         // promote this generation data to snapshot
-        if (!snapshot->promote(number_of_classes)) {
+        if (!_snapshot->promote(number_of_classes)) {
           // failed to promote, means out of memory
           MemTracker::shutdown(MemTracker::NMT_out_of_memory);
         }
@@ -140,7 +139,7 @@
         // worker thread is idle
         worker_idle = true;
         MemTracker::report_worker_idle();
-        snapshot->wait(1000);
+        _snapshot->wait(1000);
         ThreadCritical tc;
         // check if more data arrived
         if (!_gen[_head].has_more_recorder()) {
--- a/src/share/vm/services/memTrackWorker.hpp	Wed Apr 17 12:13:28 2013 -0700
+++ b/src/share/vm/services/memTrackWorker.hpp	Thu Apr 18 13:42:00 2013 -0700
@@ -85,8 +85,10 @@
 
   bool            _has_error;
 
+  MemSnapshot*    _snapshot;
+
  public:
-  MemTrackWorker();
+  MemTrackWorker(MemSnapshot* snapshot);
   ~MemTrackWorker();
   _NOINLINE_ void* operator new(size_t size);
   _NOINLINE_ void* operator new(size_t size, const std::nothrow_t& nothrow_constant);
--- a/src/share/vm/services/memTracker.cpp	Wed Apr 17 12:13:28 2013 -0700
+++ b/src/share/vm/services/memTracker.cpp	Thu Apr 18 13:42:00 2013 -0700
@@ -53,12 +53,12 @@
 }
 
 
-MemRecorder*                    MemTracker::_global_recorder = NULL;
+MemRecorder* volatile           MemTracker::_global_recorder = NULL;
 MemSnapshot*                    MemTracker::_snapshot = NULL;
 MemBaseline                     MemTracker::_baseline;
 Mutex*                          MemTracker::_query_lock = NULL;
-volatile MemRecorder*           MemTracker::_merge_pending_queue = NULL;
-volatile MemRecorder*           MemTracker::_pooled_recorders = NULL;
+MemRecorder* volatile           MemTracker::_merge_pending_queue = NULL;
+MemRecorder* volatile           MemTracker::_pooled_recorders = NULL;
 MemTrackWorker*                 MemTracker::_worker_thread = NULL;
 int                             MemTracker::_sync_point_skip_count = 0;
 MemTracker::NMTLevel            MemTracker::_tracking_level = MemTracker::NMT_off;
@@ -127,12 +127,15 @@
   assert(_state == NMT_bootstrapping_multi_thread, "wrong state");
 
   _snapshot = new (std::nothrow)MemSnapshot();
-  if (_snapshot != NULL && !_snapshot->out_of_memory()) {
-    if (start_worker()) {
+  if (_snapshot != NULL) {
+    if (!_snapshot->out_of_memory() && start_worker(_snapshot)) {
       _state = NMT_started;
       NMT_track_callsite = (_tracking_level == NMT_detail && can_walk_stack());
       return;
     }
+
+    delete _snapshot;
+    _snapshot = NULL;
   }
 
   // fail to start native memory tracking, shut it down
@@ -206,7 +209,7 @@
 // delete all pooled recorders
 void MemTracker::delete_all_pooled_recorders() {
   // free all pooled recorders
-  volatile MemRecorder* cur_head = _pooled_recorders;
+  MemRecorder* volatile cur_head = _pooled_recorders;
   if (cur_head != NULL) {
     MemRecorder* null_ptr = NULL;
     while (cur_head != NULL && (void*)cur_head != Atomic::cmpxchg_ptr((void*)null_ptr,
@@ -540,11 +543,14 @@
 /*
  * Start worker thread.
  */
-bool MemTracker::start_worker() {
-  assert(_worker_thread == NULL, "Just Check");
-  _worker_thread = new (std::nothrow) MemTrackWorker();
-  if (_worker_thread == NULL || _worker_thread->has_error()) {
-    shutdown(NMT_initialization);
+bool MemTracker::start_worker(MemSnapshot* snapshot) {
+  assert(_worker_thread == NULL && _snapshot != NULL, "Just Check");
+  _worker_thread = new (std::nothrow) MemTrackWorker(snapshot);
+  if (_worker_thread == NULL) {
+    return false;
+  } else if (_worker_thread->has_error()) {
+    delete _worker_thread;
+    _worker_thread = NULL;
     return false;
   }
   _worker_thread->start();
--- a/src/share/vm/services/memTracker.hpp	Wed Apr 17 12:13:28 2013 -0700
+++ b/src/share/vm/services/memTracker.hpp	Thu Apr 18 13:42:00 2013 -0700
@@ -349,7 +349,7 @@
 
  private:
   // start native memory tracking worker thread
-  static bool start_worker();
+  static bool start_worker(MemSnapshot* snapshot);
 
   // called by worker thread to complete shutdown process
   static void final_shutdown();
@@ -403,18 +403,18 @@
   // a thread can start to allocate memory before it is attached
   // to VM 'Thread', those memory activities are recorded here.
   // ThreadCritical is required to guard this global recorder.
-  static MemRecorder*     _global_recorder;
+  static MemRecorder* volatile _global_recorder;
 
   // main thread id
   debug_only(static intx   _main_thread_tid;)
 
   // pending recorders to be merged
-  static volatile MemRecorder*      _merge_pending_queue;
+  static MemRecorder* volatile     _merge_pending_queue;
 
   NOT_PRODUCT(static volatile jint   _pending_recorder_count;)
 
   // pooled memory recorders
-  static volatile MemRecorder*      _pooled_recorders;
+  static MemRecorder* volatile     _pooled_recorders;
 
   // memory recorder pool management, uses following
   // counter to determine if a released memory recorder
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/trace/noTraceBackend.hpp	Thu Apr 18 13:42:00 2013 -0700
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+#ifndef SHARE_VM_TRACE_NOTRACEBACKEND_HPP
+#define SHARE_VM_TRACE_NOTRACEBACKEND_HPP
+
+#include "prims/jni.h"
+
+typedef jlong TracingTime;
+typedef jlong RelativeTracingTime;
+
+class NoTraceBackend {
+public:
+  static TracingTime time() {
+    return 0;
+  }
+};
+
+typedef NoTraceBackend Tracing;
+
+#endif
+
+
--- a/src/share/vm/trace/trace.xml	Wed Apr 17 12:13:28 2013 -0700
+++ b/src/share/vm/trace/trace.xml	Thu Apr 18 13:42:00 2013 -0700
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
- Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2012, 2013, Oracle and/or its affiliates. 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
@@ -36,6 +36,7 @@
     <relation_decl id="GC_ID" uri="vm/gc/id"/>
     <relation_decl id="COMP_ID" uri="vm/compiler/id"/>
     <relation_decl id="SWEEP_ID" uri="vm/code_sweeper/id"/>
+    <relation_decl id="JAVA_MONITOR_ADDRESS" uri="java/monitor/address"/>
   </relation_decls>
 
 <!--
@@ -89,14 +90,14 @@
             has_thread="true" has_stacktrace="true" is_instant="false">
       <value type="CLASS" field="klass" label="Class Parked On"/>
       <value type="MILLIS" field="timeout" label="Park Timeout"/>
-      <value type="ADDRESS" field="address" label="Address of Object Parked"/>
+      <value type="ADDRESS" field="address" label="Address of Object Parked" relation="JAVA_MONITOR_ADDRESS"/>
     </event>
 
     <event id="JavaMonitorEnter" path="java/monitor_enter" label="Java Monitor Blocked"
             has_thread="true" has_stacktrace="true" is_instant="false">
       <value type="CLASS" field="klass" label="Monitor Class"/>
       <value type="JAVALANGTHREAD" field="previousOwner" label="Previous Monitor Owner"/>
-      <value type="ADDRESS" field="address" label="Monitor Address"/>
+      <value type="ADDRESS" field="address" label="Monitor Address" relation="JAVA_MONITOR_ADDRESS"/>
     </event>
     
     <event id="JavaMonitorWait" path="java/monitor_wait" label="Java Monitor Wait" description="Waiting on a Java monitor"
@@ -105,7 +106,20 @@
       <value type="OSTHREAD" field="notifier" label="Notifier Thread" description="Notifying Thread"/>
       <value type="MILLIS" field="timeout" label="Timeout" description="Maximum wait time"/>
       <value type="BOOLEAN" field="timedOut" label="Timed Out" description="Wait has been timed out"/>
-      <value type="ADDRESS" field="address" label="Monitor Address" description="Address of object waited on"/>
+      <value type="ADDRESS" field="address" label="Monitor Address" description="Address of object waited on" relation="JAVA_MONITOR_ADDRESS"/>
+    </event>
+
+    <event id="ClassLoad" path="vm/class/load" label="Class Load"
+            has_thread="true" has_stacktrace="true" is_instant="false">
+      <value type="CLASS" field="loadedClass" label="Loaded Class"/>
+      <value type="CLASS" field="definingClassLoader" label="Defining Class Loader"/>
+      <value type="CLASS" field="initiatingClassLoader" label="Initiating Class Loader"/>
+    </event>
+
+    <event id="ClassUnload" path="vm/class/unload" label="Class Unload"
+        has_thread="true" is_instant="true">
+      <value type="CLASS" field="unloadedClass" label="Unloaded Class"/>
+      <value type="CLASS" field="definingClassLoader" label="Defining Class Loader"/>
     </event>
 
     <struct id="VirtualSpace">
@@ -203,11 +217,10 @@
     </event>
 
     <struct id="CopyFailed">
-      <value type="BYTES64" field="objectCount" label="Object Count"/>
+      <value type="ULONG" field="objectCount" label="Object Count"/>
       <value type="BYTES64" field="firstSize" label="First Failed Object Size"/>
       <value type="BYTES64" field="smallestSize" label="Smallest Failed Object Size"/>
       <value type="BYTES64" field="totalSize" label="Total Object Size"/>
-      <value type="OSTHREAD" field="thread" label="Running thread"/>
     </struct>
 
     <event id="ObjectCountAfterGC" path="vm/gc/detailed/object_count_after_gc" is_instant="true" label="Object Count After GC">
@@ -221,6 +234,13 @@
            description="Promotion of an object failed">
       <value type="ULONG" field="gcId" label="GC ID" relation="GC_ID"/>
       <structvalue type="CopyFailed" field="data" label="data"/>
+      <value type="OSTHREAD" field="thread" label="Running thread"/>
+    </event>
+
+    <event id="EvacuationFailed" path="vm/gc/detailed/evacuation_failed" label="Evacuation Failed" is_instant="true"
+           description="Evacuation of an object failed">
+      <value type="ULONG" field="gcId" label="GC ID" relation="GC_ID"/>
+      <structvalue type="CopyFailed" field="data" label="data"/>
     </event>
 
     <event id="ConcurrentModeFailure" path="vm/gc/detailed/concurrent_mode_failure" label="Concurrent Mode Failure"
@@ -313,7 +333,7 @@
       <value type="VMOPERATIONTYPE" field="operation" label="Operation" />
       <value type="BOOLEAN" field="safepoint" label="At Safepoint" description="If the operation occured at a safepoint."/>
       <value type="BOOLEAN" field="blocking" label="Caller Blocked" description="If the calling thread was blocked until the operation was complete."/>
-      <value type="OSTHREAD" field="caller" label="Caller" transition="TO" description="Thread requesting operation. If non-blocking, will be set to 0 indicating thread is unknown."/>
+      <value type="OSTHREAD" field="caller" label="Caller" transition="FROM" description="Thread requesting operation. If non-blocking, will be set to 0 indicating thread is unknown."/>
     </event>
     
     <!-- Allocation events -->
--- a/src/share/vm/trace/traceBackend.hpp	Wed Apr 17 12:13:28 2013 -0700
+++ b/src/share/vm/trace/traceBackend.hpp	Thu Apr 18 13:42:00 2013 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. 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
@@ -32,10 +32,13 @@
 #include "runtime/os.hpp"
 
 class TraceBackend {
- public:
-  static bool enabled(TraceEventId id) {
+public:
+  static bool enabled(void) {
     return EnableTracing;
   }
+  static bool is_event_enabled(TraceEventId id) {
+    return enabled();
+  }
 
   static TracingTime time() {
     return os::elapsed_counter();
@@ -44,9 +47,16 @@
   static TracingTime time_adjustment(jlong time) {
     return time;
   }
+
+  static void on_unloading_classes(BoolObjectClosure* is_alive, int no_of_classes_unloading) {
+  }
 };
 
 typedef TraceBackend Tracing;
 
+#else /* INCLUDE_TRACE */
+
+#include "trace/noTraceBackend.hpp"
+
 #endif /* INCLUDE_TRACE */
 #endif /* SHARE_VM_TRACE_TRACEBACKEND_HPP */
--- a/src/share/vm/trace/traceEvent.hpp	Wed Apr 17 12:13:28 2013 -0700
+++ b/src/share/vm/trace/traceEvent.hpp	Thu Apr 18 13:42:00 2013 -0700
@@ -73,7 +73,7 @@
   }
 
   static bool is_enabled() {
-    return Tracing::enabled(T::eventId);
+    return Tracing::is_event_enabled(T::eventId);
   }
 
   bool should_commit() {
--- a/src/share/vm/trace/traceEventClasses.xsl	Wed Apr 17 12:13:28 2013 -0700
+++ b/src/share/vm/trace/traceEventClasses.xsl	Thu Apr 18 13:42:00 2013 -0700
@@ -37,6 +37,7 @@
 // INCLUDE_TRACE
 
 #include "memory/resourceArea.hpp"
+#include "runtime/handles.inline.hpp"
 #include "tracefiles/traceTypes.hpp"
 #include "trace/traceEvent.hpp"
 
@@ -130,6 +131,7 @@
   <xsl:value-of select="concat('  Event', @id, '(EventStartTime timing=TIMED) : TraceEvent&lt;Event', @id, '&gt;(timing) {}', $newline)"/>
   void writeEvent(void) {
     ResourceMark rm;
+    HandleMark hm;
     TraceStream ts(*tty);
     ts.print("<xsl:value-of select="@label"/>: [");
 <xsl:apply-templates select="value|structvalue" mode="write-data"/>
--- a/src/share/vm/trace/traceStream.hpp	Wed Apr 17 12:13:28 2013 -0700
+++ b/src/share/vm/trace/traceStream.hpp	Thu Apr 18 13:42:00 2013 -0700
@@ -27,9 +27,11 @@
 
 #if INCLUDE_TRACE
 
+#include "oops/klass.hpp"
+#include "oops/klassOop.hpp"
+#include "oops/methodOop.hpp"
+#include "oops/symbol.hpp"
 #include "utilities/ostream.hpp"
-#include "oops/methodOop.hpp"
-#include "oops/klassOop.hpp"
 
 class TraceStream : public StackObj {
  private:
@@ -78,12 +80,32 @@
     _st.print("%s = %f", label, val);
   }
 
-  void print_val(const char* label, klassOop& val) {
-    _st.print("%s = %s", label, val->print_string());
+  // Caller is machine generated code located in traceEventClasses.hpp
+  // Event<TraceId>::writeEvent() (pseudocode) contains the
+  // necessary ResourceMark for the resource allocations below.
+  // See traceEventClasses.xsl for details.
+  void print_val(const char* label, const klassOop& val) {
+    const char* description = "NULL";
+    if (val != NULL) {
+      Klass* myklass = val->klass_part();
+      Symbol* name = myklass->name();
+      if (name != NULL) {
+        description = name->as_C_string();
+      }
+    }
+    _st.print("%s = %s", label, description);
   }
 
-  void print_val(const char* label, methodOop& val) {
-    _st.print("%s = %s", label, val->name_and_sig_as_C_string());
+  // Caller is machine generated code located in traceEventClasses.hpp
+  // Event<TraceId>::writeEvent() (pseudocode) contains the
+  // necessary ResourceMark for the resource allocations below.
+  // See traceEventClasses.xsl for details.
+  void print_val(const char* label, const methodOop& val) {
+    const char* description = "NULL";
+    if (val != NULL) {
+      description = val->name_and_sig_as_C_string();
+    }
+    _st.print("%s = %s", label, description);
   }
 
   void print_val(const char* label, const char* val) {
@@ -95,5 +117,5 @@
   }
 };
 
-#endif
-#endif
+#endif /* INCLUDE_TRACE */
+#endif /* SHARE_VM_TRACE_TRACESTREAM_HPP */
--- a/src/share/vm/trace/tracetypes.xml	Wed Apr 17 12:13:28 2013 -0700
+++ b/src/share/vm/trace/tracetypes.xml	Thu Apr 18 13:42:00 2013 -0700
@@ -103,6 +103,7 @@
 
     <content_type id="StackTrace" hr_name="Stacktrace"
                   type="U8" builtin_type="STACKTRACE">
+      <value type="BOOLEAN" field="truncated" label="Truncated"/>
       <structarray type="StackFrame" field="frames" label="Stack frames"/>
     </content_type>