changeset 10189:3637ec3e50c2

8079408: Reimplement TraceClassLoading, TraceClassUnloading, and TraceClassLoaderData with Unified Logging. Summary: TraceClassLoading, TraceClassUnloading, and TraceClassLoaderData have been reimplemented using Unified logging. Reviewed-by: iklam, coleenp, dholmes, jiangli, hseigel, rprotacio Contributed-by: max.ockner@oracle.com, ioi.lam@oracle.com
author mockner
date Wed, 03 Feb 2016 11:40:30 -0500
parents 04a9132aa6e4
children 49bb4aa253c3
files src/share/vm/classfile/classFileParser.cpp src/share/vm/classfile/classLoader.cpp src/share/vm/classfile/classLoaderData.cpp src/share/vm/classfile/classLoaderData.hpp src/share/vm/classfile/javaClasses.cpp src/share/vm/classfile/systemDictionary.cpp src/share/vm/code/nmethod.cpp src/share/vm/logging/logTag.hpp src/share/vm/memory/filemap.cpp src/share/vm/oops/instanceKlass.cpp src/share/vm/oops/instanceKlass.hpp src/share/vm/oops/klass.cpp src/share/vm/prims/jvmtiEnv.cpp src/share/vm/prims/whitebox.cpp src/share/vm/runtime/arguments.cpp src/share/vm/runtime/globals.hpp src/share/vm/services/classLoadingService.cpp src/share/vm/services/classLoadingService.hpp test/compiler/jsr292/CallSiteDepContextTest.java test/runtime/logging/ClassLoadUnloadTest.java test/runtime/logging/classes/test/Empty.java test/runtime/testlibrary/ClassUnloadCommon.java
diffstat 22 files changed, 357 insertions(+), 121 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/vm/classfile/classFileParser.cpp	Tue Feb 02 14:54:05 2016 +0000
+++ b/src/share/vm/classfile/classFileParser.cpp	Wed Feb 03 11:40:30 2016 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, 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
@@ -34,6 +34,7 @@
 #include "classfile/verifier.hpp"
 #include "classfile/vmSymbols.hpp"
 #include "gc/shared/gcLocker.hpp"
+#include "logging/log.hpp"
 #include "memory/allocation.hpp"
 #include "memory/metadataFactory.hpp"
 #include "memory/oopFactory.hpp"
@@ -5347,30 +5348,12 @@
   ClassLoadingService::notify_class_loaded(ik, false /* not shared class */);
 
   if (!is_internal()) {
-    if (TraceClassLoading) {
-      ResourceMark rm;
-      // print in a single call to reduce interleaving of output
-      if (_stream->source() != NULL) {
-        tty->print("[Loaded %s from %s]\n",
-                   ik->external_name(),
-                   _stream->source());
-      } else if (_loader_data->class_loader() == NULL) {
-        const Klass* const caller =
-          THREAD->is_Java_thread()
-                ? ((JavaThread*)THREAD)->security_get_caller_class(1)
-                : NULL;
-        // caller can be NULL, for example, during a JVMTI VM_Init hook
-        if (caller != NULL) {
-          tty->print("[Loaded %s by instance of %s]\n",
-                     ik->external_name(),
-                     caller->external_name());
-        } else {
-          tty->print("[Loaded %s]\n", ik->external_name());
-        }
-      } else {
-        tty->print("[Loaded %s from %s]\n", ik->external_name(),
-                   _loader_data->class_loader()->klass()->external_name());
-      }
+    if (log_is_enabled(Info, classload)) {
+      ik->print_loading_log(LogLevel::Info, _loader_data, _stream);
+    }
+    // No 'else' here as logging levels are not mutually exclusive
+    if (log_is_enabled(Debug, classload)) {
+      ik->print_loading_log(LogLevel::Debug, _loader_data, _stream);
     }
 
     if (log_is_enabled(Info, classresolve))  {
--- a/src/share/vm/classfile/classLoader.cpp	Tue Feb 02 14:54:05 2016 +0000
+++ b/src/share/vm/classfile/classLoader.cpp	Wed Feb 03 11:40:30 2016 -0500
@@ -578,15 +578,14 @@
         }
       }
     }
-    if (TraceClassLoading || TraceClassPaths) {
+    if (TraceClassPaths) {
       tty->print_cr("[Opened %s]", path);
     }
+    log_info(classload)("opened: %s", path);
   } else {
     // Directory
     new_entry = new ClassPathDirEntry(path);
-    if (TraceClassLoading) {
-      tty->print_cr("[Path %s]", path);
-    }
+    log_info(classload)("path: %s", path);
   }
   return new_entry;
 }
--- a/src/share/vm/classfile/classLoaderData.cpp	Tue Feb 02 14:54:05 2016 +0000
+++ b/src/share/vm/classfile/classLoaderData.cpp	Wed Feb 03 11:40:30 2016 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, 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
@@ -54,12 +54,14 @@
 #include "classfile/systemDictionary.hpp"
 #include "code/codeCache.hpp"
 #include "gc/shared/gcLocker.hpp"
+#include "logging/log.hpp"
 #include "memory/metadataFactory.hpp"
 #include "memory/metaspaceShared.hpp"
 #include "memory/oopFactory.hpp"
 #include "oops/objArrayOop.inline.hpp"
 #include "oops/oop.inline.hpp"
 #include "runtime/atomic.inline.hpp"
+#include "runtime/javaCalls.hpp"
 #include "runtime/jniHandles.hpp"
 #include "runtime/mutex.hpp"
 #include "runtime/safepoint.hpp"
@@ -286,9 +288,9 @@
     _klasses = k;
   }
 
-  if (publicize && TraceClassLoaderData && Verbose && k->class_loader_data() != NULL) {
+  if (publicize && k->class_loader_data() != NULL) {
     ResourceMark rm;
-    tty->print_cr("[TraceClassLoaderData] Adding k: " PTR_FORMAT " %s to CLD: "
+    log_trace(classloaderdata)("Adding k: " PTR_FORMAT " %s to CLD: "
                   PTR_FORMAT " loader: " PTR_FORMAT " %s",
                   p2i(k),
                   k->external_name(),
@@ -326,15 +328,16 @@
   // Tell serviceability tools these classes are unloading
   classes_do(InstanceKlass::notify_unload_class);
 
-  if (TraceClassLoaderData) {
+  if (log_is_enabled(Debug, classloaderdata)) {
     ResourceMark rm;
-    tty->print("[ClassLoaderData: unload loader data " INTPTR_FORMAT, p2i(this));
-    tty->print(" for instance " INTPTR_FORMAT " of %s", p2i((void *)class_loader()),
+    outputStream* log = LogHandle(classloaderdata)::debug_stream();
+    log->print(": unload loader data " INTPTR_FORMAT, p2i(this));
+    log->print(" for instance " INTPTR_FORMAT " of %s", p2i((void *)class_loader()),
                loader_name());
     if (is_anonymous()) {
-      tty->print(" for anonymous class  " INTPTR_FORMAT " ", p2i(_klasses));
+      log->print(" for anonymous class  " INTPTR_FORMAT " ", p2i(_klasses));
     }
-    tty->print_cr("]");
+    log->cr();
   }
 }
 
@@ -408,13 +411,13 @@
       assert (class_loader() == NULL, "Must be");
       set_metaspace(new Metaspace(_metaspace_lock, Metaspace::BootMetaspaceType));
     } else if (is_anonymous()) {
-      if (TraceClassLoaderData && Verbose && class_loader() != NULL) {
-        tty->print_cr("is_anonymous: %s", class_loader()->klass()->internal_name());
+      if (class_loader() != NULL) {
+        log_trace(classloaderdata)("is_anonymous: %s", class_loader()->klass()->internal_name());
       }
       set_metaspace(new Metaspace(_metaspace_lock, Metaspace::AnonymousMetaspaceType));
     } else if (class_loader()->is_a(SystemDictionary::reflect_DelegatingClassLoader_klass())) {
-      if (TraceClassLoaderData && Verbose && class_loader() != NULL) {
-        tty->print_cr("is_reflection: %s", class_loader()->klass()->internal_name());
+      if (class_loader() != NULL) {
+        log_trace(classloaderdata)("is_reflection: %s", class_loader()->klass()->internal_name());
       }
       set_metaspace(new Metaspace(_metaspace_lock, Metaspace::ReflectionMetaspaceType));
     } else {
@@ -601,21 +604,47 @@
     cld->set_next(next);
     ClassLoaderData* exchanged = (ClassLoaderData*)Atomic::cmpxchg_ptr(cld, list_head, next);
     if (exchanged == next) {
-      if (TraceClassLoaderData) {
-        ResourceMark rm;
-        tty->print("[ClassLoaderData: ");
-        tty->print("create class loader data " INTPTR_FORMAT, p2i(cld));
-        tty->print(" for instance " INTPTR_FORMAT " of %s", p2i((void *)cld->class_loader()),
-                   cld->loader_name());
-        tty->print_cr("]");
+      if (log_is_enabled(Debug, classloaderdata)) {
+       PauseNoSafepointVerifier pnsv(&no_safepoints); // Need safe points for JavaCalls::call_virtual
+       log_creation(loader, cld, CHECK_NULL);
       }
       return cld;
     }
     next = exchanged;
   } while (true);
+}
 
+void ClassLoaderDataGraph::log_creation(Handle loader, ClassLoaderData* cld, TRAPS) {
+  Handle string;
+  if (loader.not_null()) {
+    // Include the result of loader.toString() in the output. This allows
+    // the user of the log to identify the class loader instance.
+    JavaValue result(T_OBJECT);
+    KlassHandle spec_klass(THREAD, SystemDictionary::ClassLoader_klass());
+    JavaCalls::call_virtual(&result,
+                            loader,
+                            spec_klass,
+                            vmSymbols::toString_name(),
+                            vmSymbols::void_string_signature(),
+                            CHECK);
+    assert(result.get_type() == T_OBJECT, "just checking");
+    string = (oop)result.get_jobject();
+  }
+
+  ResourceMark rm;
+  outputStream* log = LogHandle(classloaderdata)::debug_stream();
+  log->print("create class loader data " INTPTR_FORMAT, p2i(cld));
+  log->print(" for instance " INTPTR_FORMAT " of %s", p2i((void *)cld->class_loader()),
+             cld->loader_name());
+
+  if (string.not_null()) {
+    log->print(": ");
+    java_lang_String::print(string(), log);
+  }
+  log->cr();
 }
 
+
 void ClassLoaderDataGraph::oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) {
   for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
     cld->oops_do(f, klass_closure, must_claim);
@@ -709,10 +738,11 @@
     if (!curr->claimed()) {
       array->push(curr);
 
-      if (TraceClassLoaderData) {
-        tty->print("[ClassLoaderData] found new CLD: ");
-        curr->print_value_on(tty);
-        tty->cr();
+      if (log_is_enabled(Debug, classloaderdata)) {
+        outputStream* log = LogHandle(classloaderdata)::debug_stream();
+        log->print("found new CLD: ");
+        curr->print_value_on(log);
+        log->cr();
       }
     }
 
--- a/src/share/vm/classfile/classLoaderData.hpp	Tue Feb 02 14:54:05 2016 +0000
+++ b/src/share/vm/classfile/classLoaderData.hpp	Wed Feb 03 11:40:30 2016 -0500
@@ -116,6 +116,7 @@
   static void dump_on(outputStream * const out) PRODUCT_RETURN;
   static void dump() { dump_on(tty); }
   static void verify();
+  static void log_creation(Handle loader, ClassLoaderData* cld, TRAPS);
 
   static bool unload_list_contains(const void* x);
 #ifndef PRODUCT
--- a/src/share/vm/classfile/javaClasses.cpp	Tue Feb 02 14:54:05 2016 +0000
+++ b/src/share/vm/classfile/javaClasses.cpp	Wed Feb 03 11:40:30 2016 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -129,7 +129,7 @@
       tty->print_cr("  name: %s, sig: %s, flags: %08x", fs.name()->as_C_string(), fs.signature()->as_C_string(), fs.access_flags().as_int());
     }
 #endif //PRODUCT
-    vm_exit_during_initialization("Invalid layout of preloaded class: use -XX:+TraceClassLoading to see the origin of the problem class");
+    vm_exit_during_initialization("Invalid layout of preloaded class: use -Xlog:classload=info to see the origin of the problem class");
   }
   dest_offset = fd.offset();
 }
@@ -3958,7 +3958,7 @@
     tty->print_cr("  name: %s, sig: %s, flags: %08x", fs.name()->as_C_string(), fs.signature()->as_C_string(), fs.access_flags().as_int());
   }
 #endif //PRODUCT
-  vm_exit_during_initialization("Invalid layout of preloaded class: use -XX:+TraceClassLoading to see the origin of the problem class");
+  vm_exit_during_initialization("Invalid layout of preloaded class: use -Xlog:classload=info to see the origin of the problem class");
   return -1;
 }
 
--- a/src/share/vm/classfile/systemDictionary.cpp	Tue Feb 02 14:54:05 2016 +0000
+++ b/src/share/vm/classfile/systemDictionary.cpp	Wed Feb 03 11:40:30 2016 -0500
@@ -1302,14 +1302,13 @@
       ik->restore_unshareable_info(loader_data, protection_domain, CHECK_(nh));
     }
 
-    if (TraceClassLoading) {
-      ResourceMark rm;
-      tty->print("[Loaded %s", ik->external_name());
-      tty->print(" from shared objects file");
-      if (class_loader.not_null()) {
-        tty->print(" by %s", loader_data->loader_name());
-      }
-      tty->print_cr("]");
+    if (log_is_enabled(Info, classload)) {
+      ik()->print_loading_log(LogLevel::Info, loader_data, NULL);
+    }
+    // No 'else' here as logging levels are not mutually exclusive
+
+    if (log_is_enabled(Debug, classload)) {
+      ik()->print_loading_log(LogLevel::Debug, loader_data, NULL);
     }
 
     if (DumpLoadedClassList != NULL && classlist_file->is_open()) {
--- a/src/share/vm/code/nmethod.cpp	Tue Feb 02 14:54:05 2016 +0000
+++ b/src/share/vm/code/nmethod.cpp	Wed Feb 03 11:40:30 2016 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -48,6 +48,7 @@
 #include "utilities/dtrace.hpp"
 #include "utilities/events.hpp"
 #include "utilities/xmlstream.hpp"
+#include "logging/log.hpp"
 #ifdef TARGET_ARCH_x86
 # include "nativeInst_x86.hpp"
 #endif
@@ -1310,13 +1311,14 @@
   flush_dependencies(is_alive);
 
   // Break cycle between nmethod & method
-  if (TraceClassUnloading && WizardMode) {
-    tty->print_cr("[Class unloading: Making nmethod " INTPTR_FORMAT
-                  " unloadable], Method*(" INTPTR_FORMAT
+  if (log_is_enabled(Trace, classunload)) {
+    outputStream* log = LogHandle(classunload)::trace_stream();
+    log->print_cr("making nmethod " INTPTR_FORMAT
+                  " unloadable, Method*(" INTPTR_FORMAT
                   "), cause(" INTPTR_FORMAT ")",
                   p2i(this), p2i(_method), p2i(cause));
     if (!Universe::heap()->is_gc_active())
-      cause->klass()->print();
+      cause->klass()->print_on(log);
   }
   // Unlink the osr method, so we do not look this up again
   if (is_osr_method()) {
--- a/src/share/vm/logging/logTag.hpp	Tue Feb 02 14:54:05 2016 +0000
+++ b/src/share/vm/logging/logTag.hpp	Wed Feb 03 11:40:30 2016 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -39,6 +39,9 @@
   LOG_TAG(classhisto) \
   LOG_TAG(classresolve) \
   LOG_TAG(classinit) \
+  LOG_TAG(classload) /* Trace all classes loaded */ \
+  LOG_TAG(classloaderdata) /* class loader loader_data lifetime */ \
+  LOG_TAG(classunload) /* Trace unloading of classes */ \
   LOG_TAG(comp) \
   LOG_TAG(compaction) \
   LOG_TAG(cpu) \
--- a/src/share/vm/memory/filemap.cpp	Tue Feb 02 14:54:05 2016 +0000
+++ b/src/share/vm/memory/filemap.cpp	Wed Feb 03 11:40:30 2016 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, 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
@@ -208,7 +208,7 @@
         count ++;
         bytes += (int)entry_size;
         bytes += name_bytes;
-        if (TraceClassPaths || (TraceClassLoading && Verbose)) {
+        if (TraceClassPaths) {
           tty->print_cr("[Add main shared path (%s) %s]", (cpe->is_jar_file() ? "jar" : "dir"), name);
         }
       } else {
@@ -275,7 +275,7 @@
     struct stat st;
     const char* name = ent->_name;
     bool ok = true;
-    if (TraceClassPaths || (TraceClassLoading && Verbose)) {
+    if (TraceClassPaths) {
       tty->print_cr("[Checking shared classpath entry: %s]", name);
     }
     if (os::stat(name, &st) != 0) {
@@ -301,7 +301,7 @@
       }
     }
     if (ok) {
-      if (TraceClassPaths || (TraceClassLoading && Verbose)) {
+      if (TraceClassPaths) {
         tty->print_cr("[ok]");
       }
     } else if (!PrintSharedArchiveAndExit) {
--- a/src/share/vm/oops/instanceKlass.cpp	Tue Feb 02 14:54:05 2016 +0000
+++ b/src/share/vm/oops/instanceKlass.cpp	Wed Feb 03 11:40:30 2016 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, 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
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "classfile/classFileParser.hpp"
+#include "classfile/classFileStream.hpp"
 #include "classfile/javaClasses.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "classfile/verifier.hpp"
@@ -35,6 +36,7 @@
 #include "interpreter/oopMapCache.hpp"
 #include "interpreter/rewriter.hpp"
 #include "jvmtifiles/jvmti.h"
+#include "logging/log.hpp"
 #include "memory/heapInspection.hpp"
 #include "memory/iterator.inline.hpp"
 #include "memory/metadataFactory.hpp"
@@ -2904,6 +2906,79 @@
   return external_name();
 }
 
+void InstanceKlass::print_loading_log(LogLevel::type type,
+                                      ClassLoaderData* loader_data,
+                                      const ClassFileStream* cfs) const {
+  ResourceMark rm;
+  outputStream* log;
+
+  assert(type == LogLevel::Info || type == LogLevel::Debug, "sanity");
+
+  if (type == LogLevel::Info) {
+    log = LogHandle(classload)::info_stream();
+  } else {
+    assert(type == LogLevel::Debug,
+           "print_loading_log supports only Debug and Info levels");
+    log = LogHandle(classload)::debug_stream();
+  }
+
+  // Name and class hierarchy info
+  log->print("%s", external_name());
+
+  // Source
+  if (cfs != NULL) {
+    if (cfs->source() != NULL) {
+      log->print(" source: %s", cfs->source());
+    } else if (loader_data == ClassLoaderData::the_null_class_loader_data()) {
+      Thread* THREAD = Thread::current();
+      Klass* caller =
+            THREAD->is_Java_thread()
+                ? ((JavaThread*)THREAD)->security_get_caller_class(1)
+                : NULL;
+      // caller can be NULL, for example, during a JVMTI VM_Init hook
+      if (caller != NULL) {
+        log->print(" source: instance of %s", caller->external_name());
+      } else {
+        // source is unknown
+      }
+    } else {
+      Handle class_loader(loader_data->class_loader());
+      log->print(" source: %s", class_loader->klass()->external_name());
+    }
+  } else {
+    log->print(" source: shared objects file");
+  }
+
+  if (type == LogLevel::Debug) {
+    // Class hierarchy info
+    log->print(" klass: " INTPTR_FORMAT " super: " INTPTR_FORMAT,
+               p2i(this),  p2i(superklass()));
+
+    if (local_interfaces() != NULL && local_interfaces()->length() > 0) {
+      log->print(" interfaces:");
+      int length = local_interfaces()->length();
+      for (int i = 0; i < length; i++) {
+        log->print(" " INTPTR_FORMAT,
+                   p2i(InstanceKlass::cast(local_interfaces()->at(i))));
+      }
+    }
+
+    // Class loader
+    log->print(" loader: [");
+    loader_data->print_value_on(log);
+    log->print("]");
+
+    // Classfile checksum
+    if (cfs) {
+      log->print(" bytes: %d checksum: %08x",
+                 cfs->length(),
+                 ClassLoader::crc32(0, (const char*)cfs->buffer(),
+                 cfs->length()));
+    }
+  }
+  log->cr();
+}
+
 #if INCLUDE_SERVICES
 // Size Statistics
 void InstanceKlass::collect_statistics(KlassSizeStats *sz) const {
--- a/src/share/vm/oops/instanceKlass.hpp	Tue Feb 02 14:54:05 2016 +0000
+++ b/src/share/vm/oops/instanceKlass.hpp	Wed Feb 03 11:40:30 2016 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, 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
@@ -27,6 +27,7 @@
 
 #include "classfile/classLoaderData.hpp"
 #include "gc/shared/specialized_oop_closures.hpp"
+#include "logging/logLevel.hpp"
 #include "memory/referenceType.hpp"
 #include "oops/annotations.hpp"
 #include "oops/constMethod.hpp"
@@ -1244,6 +1245,9 @@
   void verify_on(outputStream* st);
 
   void oop_verify_on(oop obj, outputStream* st);
+
+  // Logging
+  void print_loading_log(LogLevel::type type, ClassLoaderData* loader_data, const ClassFileStream* cfs) const;
 };
 
 // for adding methods
--- a/src/share/vm/oops/klass.cpp	Tue Feb 02 14:54:05 2016 +0000
+++ b/src/share/vm/oops/klass.cpp	Wed Feb 03 11:40:30 2016 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, 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
@@ -28,6 +28,7 @@
 #include "classfile/systemDictionary.hpp"
 #include "classfile/vmSymbols.hpp"
 #include "gc/shared/collectedHeap.inline.hpp"
+#include "logging/log.hpp"
 #include "memory/heapInspection.hpp"
 #include "memory/metadataFactory.hpp"
 #include "memory/oopFactory.hpp"
@@ -386,9 +387,9 @@
     Klass* sub = current->subklass();
     while (sub != NULL && !sub->is_loader_alive(is_alive)) {
 #ifndef PRODUCT
-      if (TraceClassUnloading && WizardMode) {
+      if (log_is_enabled(Trace, classunload)) {
         ResourceMark rm;
-        tty->print_cr("[Unlinking class (subclass) %s]", sub->external_name());
+        log_trace(classunload)("unlinking class (subclass): %s", sub->external_name());
       }
 #endif
       sub = sub->next_sibling();
@@ -401,9 +402,9 @@
     // Find and set the first alive sibling
     Klass* sibling = current->next_sibling();
     while (sibling != NULL && !sibling->is_loader_alive(is_alive)) {
-      if (TraceClassUnloading && WizardMode) {
+      if (log_is_enabled(Trace, classunload)) {
         ResourceMark rm;
-        tty->print_cr("[Unlinking class (sibling) %s]", sibling->external_name());
+        log_trace(classunload)("[Unlinking class (sibling) %s]", sibling->external_name());
       }
       sibling = sibling->next_sibling();
     }
--- a/src/share/vm/prims/jvmtiEnv.cpp	Tue Feb 02 14:54:05 2016 +0000
+++ b/src/share/vm/prims/jvmtiEnv.cpp	Wed Feb 03 11:40:30 2016 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, 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
@@ -29,6 +29,7 @@
 #include "interpreter/bytecodeStream.hpp"
 #include "interpreter/interpreter.hpp"
 #include "jvmtifiles/jvmtiEnv.hpp"
+#include "logging/log.hpp"
 #include "logging/logConfiguration.hpp"
 #include "memory/resourceArea.hpp"
 #include "memory/universe.inline.hpp"
@@ -473,9 +474,7 @@
     ObjectLocker ol(loader_lock, thread);
 
     // add the jar file to the bootclasspath
-    if (TraceClassLoading) {
-      tty->print_cr("[Opened %s]", zip_entry->name());
-    }
+    log_info(classload)("opened: %s", zip_entry->name());
     ClassLoaderExt::append_boot_classpath(zip_entry);
     return JVMTI_ERROR_NONE;
   } else {
@@ -625,8 +624,13 @@
     // ignore
     break;
   case JVMTI_VERBOSE_CLASS:
-    TraceClassLoading = value != 0;
-    TraceClassUnloading = value != 0;
+    if (value == 0) {
+      LogConfiguration::parse_log_arguments("stdout", "classunload=off", NULL, NULL, NULL);
+      LogConfiguration::parse_log_arguments("stdout", "classload=off", NULL, NULL, NULL);
+    } else {
+      LogConfiguration::parse_log_arguments("stdout", "classload=info", NULL, NULL, NULL);
+      LogConfiguration::parse_log_arguments("stdout", "classunload=info", NULL, NULL, NULL);
+    }
     break;
   case JVMTI_VERBOSE_GC:
     if (value == 0) {
--- a/src/share/vm/prims/whitebox.cpp	Tue Feb 02 14:54:05 2016 +0000
+++ b/src/share/vm/prims/whitebox.cpp	Wed Feb 03 11:40:30 2016 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, 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
@@ -1407,7 +1407,7 @@
   if (res == NULL) {
     tty->print_cr("Invalid layout of %s at %s", ik->external_name(),
         name_symbol->as_C_string());
-    vm_exit_during_initialization("Invalid layout of preloaded class: use -XX:+TraceClassLoading to see the origin of the problem class");
+    vm_exit_during_initialization("Invalid layout of preloaded class: use -Xlog:classload=info to see the origin of the problem class");
   }
 
   //fetch the field at the offset we've found
--- a/src/share/vm/runtime/arguments.cpp	Tue Feb 02 14:54:05 2016 +0000
+++ b/src/share/vm/runtime/arguments.cpp	Wed Feb 03 11:40:30 2016 -0500
@@ -402,10 +402,12 @@
 };
 
 static AliasedLoggingFlag const aliased_logging_flags[] = {
-  { "TraceClassResolution", LogLevel::Info, true, LogTag::_classresolve },
-  { "TraceExceptions", LogLevel::Info, true, LogTag::_exceptions },
-  { "TraceMonitorInflation", LogLevel::Debug, true, LogTag::_monitorinflation },
-  { NULL, LogLevel::Off, false, LogTag::__NO_TAG }
+  { "TraceClassLoading",         LogLevel::Info,  true,  LogTag::_classload },
+  { "TraceClassUnloading",       LogLevel::Info,  true,  LogTag::_classunload },
+  { "TraceClassResolution",      LogLevel::Info,  true,  LogTag::_classresolve },
+  { "TraceExceptions",           LogLevel::Info,  true,  LogTag::_exceptions },
+  { "TraceMonitorInflation",     LogLevel::Debug, true,  LogTag::_monitorinflation },
+  { NULL,                        LogLevel::Off,   false, LogTag::__NO_TAG }
 };
 
 // Return true if "v" is less than "other", where "other" may be "undefined".
@@ -2653,12 +2655,8 @@
     // -verbose:[class/gc/jni]
     if (match_option(option, "-verbose", &tail)) {
       if (!strcmp(tail, ":class") || !strcmp(tail, "")) {
-        if (FLAG_SET_CMDLINE(bool, TraceClassLoading, true) != Flag::SUCCESS) {
-          return JNI_EINVAL;
-        }
-        if (FLAG_SET_CMDLINE(bool, TraceClassUnloading, true) != Flag::SUCCESS) {
-          return JNI_EINVAL;
-        }
+        LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(classload));
+        LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(classunload));
       } else if (!strcmp(tail, ":gc")) {
         LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(gc));
       } else if (!strcmp(tail, ":jni")) {
--- a/src/share/vm/runtime/globals.hpp	Tue Feb 02 14:54:05 2016 +0000
+++ b/src/share/vm/runtime/globals.hpp	Wed Feb 03 11:40:30 2016 -0500
@@ -2416,21 +2416,12 @@
   product(bool, TraceClassPaths, false,                                     \
           "Trace processing of class paths")                                \
                                                                             \
-  product_rw(bool, TraceClassLoading, false,                                \
-          "Trace all classes loaded")                                       \
-                                                                            \
   product(bool, TraceClassLoadingPreorder, false,                           \
           "Trace all classes loaded in order referenced (not loaded)")      \
                                                                             \
-  product_rw(bool, TraceClassUnloading, false,                              \
-          "Trace unloading of classes")                                     \
-                                                                            \
   product_rw(bool, TraceLoaderConstraints, false,                           \
           "Trace loader constraints")                                       \
                                                                             \
-  develop(bool, TraceClassLoaderData, false,                                \
-          "Trace class loader loader_data lifetime")                        \
-                                                                            \
   product(size_t, InitialBootClassLoaderMetaspaceSize,                      \
           NOT_LP64(2200*K) LP64_ONLY(4*M),                                  \
           "Initial size of the boot class loader data metaspace")           \
--- a/src/share/vm/services/classLoadingService.cpp	Tue Feb 02 14:54:05 2016 +0000
+++ b/src/share/vm/services/classLoadingService.cpp	Wed Feb 03 11:40:30 2016 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, 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
@@ -33,6 +33,8 @@
 #include "utilities/dtrace.hpp"
 #include "utilities/macros.hpp"
 #include "utilities/defaultStream.hpp"
+#include "logging/log.hpp"
+#include "logging/logConfiguration.hpp"
 
 #ifdef DTRACE_ENABLED
 
@@ -135,9 +137,9 @@
     }
   }
 
-  if (TraceClassUnloading) {
+  if (log_is_enabled(Info, classunload)) {
     ResourceMark rm;
-    tty->print_cr("[Unloading class %s " INTPTR_FORMAT "]", k->external_name(), p2i(k));
+    log_info(classunload)("unloading class %s " INTPTR_FORMAT , k->external_name(), p2i(k));
   }
 }
 
@@ -179,12 +181,13 @@
 
 bool ClassLoadingService::set_verbose(bool verbose) {
   MutexLocker m(Management_lock);
-
   // verbose will be set to the previous value
-  Flag::Error error = CommandLineFlags::boolAtPut("TraceClassLoading", &verbose, Flag::MANAGEMENT);
-  assert(error==Flag::SUCCESS, "Setting TraceClassLoading flag failed with error %s", Flag::flag_error_str(error));
+  if (verbose) {
+    LogConfiguration::parse_log_arguments("stdout", "classload=info", NULL, NULL, NULL);
+  } else {
+    LogConfiguration::parse_log_arguments("stdout", "classload=off", NULL, NULL, NULL);
+  }
   reset_trace_class_unloading();
-
   return verbose;
 }
 
@@ -192,8 +195,11 @@
 void ClassLoadingService::reset_trace_class_unloading() {
   assert(Management_lock->owned_by_self(), "Must own the Management_lock");
   bool value = MemoryService::get_verbose() || ClassLoadingService::get_verbose();
-  Flag::Error error = CommandLineFlags::boolAtPut("TraceClassUnloading", &value, Flag::MANAGEMENT);
-  assert(error==Flag::SUCCESS, "Setting TraceClassUnLoading flag failed with error %s", Flag::flag_error_str(error));
+  if (value) {
+    LogConfiguration::parse_log_arguments("stdout", "classunload=info", NULL, NULL, NULL);
+  } else {
+    LogConfiguration::parse_log_arguments("stdout", "classunload=off", NULL, NULL, NULL);
+  }
 }
 
 GrowableArray<KlassHandle>* LoadedClassesEnumerator::_loaded_classes = NULL;
--- a/src/share/vm/services/classLoadingService.hpp	Tue Feb 02 14:54:05 2016 +0000
+++ b/src/share/vm/services/classLoadingService.hpp	Wed Feb 03 11:40:30 2016 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, 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
@@ -25,6 +25,7 @@
 #ifndef SHARE_VM_SERVICES_CLASSLOADINGSERVICE_HPP
 #define SHARE_VM_SERVICES_CLASSLOADINGSERVICE_HPP
 
+#include "logging/log.hpp"
 #include "runtime/handles.hpp"
 #include "runtime/perfData.hpp"
 #include "utilities/growableArray.hpp"
@@ -54,7 +55,7 @@
 public:
   static void init();
 
-  static bool get_verbose() { return TraceClassLoading; }
+  static bool get_verbose() { return log_is_enabled(Info, classload); }
   static bool set_verbose(bool verbose);
   static void reset_trace_class_unloading() NOT_MANAGEMENT_RETURN;
 
--- a/test/compiler/jsr292/CallSiteDepContextTest.java	Tue Feb 02 14:54:05 2016 +0000
+++ b/test/compiler/jsr292/CallSiteDepContextTest.java	Wed Feb 03 11:40:30 2016 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -24,7 +24,7 @@
 /**
  * @test
  * @bug 8057967
- * @run main/bootclasspath -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+TraceClassUnloading
+ * @run main/bootclasspath -Xbatch -XX:+IgnoreUnrecognizedVMOptions -Xlog:classunload
  *                         -XX:+PrintCompilation -XX:+TraceDependencies -XX:+TraceReferenceGC
  *                         -verbose:gc java.lang.invoke.CallSiteDepContextTest
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/runtime/logging/ClassLoadUnloadTest.java	Wed Feb 03 11:40:30 2016 -0500
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+
+/*
+ * @test ClassLoadUnloadTest
+ * @bug 8142506
+ * @library /testlibrary /runtime/testlibrary
+ * @library classes
+ * @build ClassUnloadCommon test.Empty jdk.test.lib.* jdk.test.lib.OutputAnalyzer jdk.test.lib.ProcessTools
+ * @run driver ClassLoadUnloadTest
+ */
+
+import jdk.test.lib.*;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class ClassLoadUnloadTest {
+    private static OutputAnalyzer out;
+    private static ProcessBuilder pb;
+    private static class ClassUnloadTestMain {
+        public static void main(String... args) throws Exception {
+            String className = "test.Empty";
+            ClassLoader cl = ClassUnloadCommon.newClassLoader();
+            Class<?> c = cl.loadClass(className);
+            cl = null; c = null;
+            ClassUnloadCommon.triggerUnloading();
+        }
+    }
+
+    static void checkFor(String... outputStrings) throws Exception {
+        out = new OutputAnalyzer(pb.start());
+        for (String s: outputStrings) {
+            out.shouldContain(s);
+        }
+        out.shouldHaveExitValue(0);
+    }
+
+    static void checkAbsent(String... outputStrings) throws Exception {
+        out = new OutputAnalyzer(pb.start());
+        for (String s: outputStrings) {
+            out.shouldNotContain(s);
+        }
+        out.shouldHaveExitValue(0);
+    }
+
+    // Use the same command-line heap size setting as ../ClassUnload/UnloadTest.java
+    static ProcessBuilder exec(String... args) throws Exception {
+        List<String> argsList = new ArrayList<>();
+        Collections.addAll(argsList, args);
+        Collections.addAll(argsList, "-Xmn8m");
+        Collections.addAll(argsList, "-Dtest.classes=" + System.getProperty("test.classes","."));
+        Collections.addAll(argsList, ClassUnloadTestMain.class.getName());
+        return ProcessTools.createJavaProcessBuilder(argsList.toArray(new String[argsList.size()]));
+    }
+
+    public static void main(String... args) throws Exception {
+
+        //  -Xlog:classunload=info
+        pb = exec("-Xlog:classunload=info");
+        checkFor("[classunload]", "unloading class");
+
+        //  -Xlog:classunload=off
+        pb = exec("-Xlog:classunload=off");
+        checkAbsent("[classunload]");
+
+        //  -XX:+TraceClassUnloading
+        pb = exec("-XX:+TraceClassUnloading");
+        checkFor("[classunload]", "unloading class");
+
+        //  -XX:-TraceClassUnloading
+        pb = exec("-XX:-TraceClassUnloading");
+        checkAbsent("[classunload]");
+
+        //  -Xlog:classload=info
+        pb = exec("-Xlog:classload=info");
+        checkFor("[classload]", "java.lang.Object", "source:");
+
+        //  -Xlog:classload=debug
+        pb = exec("-Xlog:classload=debug");
+        checkFor("[classload]", "java.lang.Object", "source:", "klass:", "super:", "loader:", "bytes:");
+
+        //  -Xlog:classload=off
+        pb = exec("-Xlog:classload=off");
+        checkAbsent("[classload]");
+
+        //  -XX:+TraceClassLoading
+        pb = exec("-XX:+TraceClassLoading");
+        checkFor("[classload]", "java.lang.Object", "source:");
+
+        //  -XX:-TraceClassLoading
+        pb = exec("-XX:-TraceClassLoading");
+        checkAbsent("[classload]");
+
+        //  -verbose:class
+        pb = exec("-verbose:class");
+        checkFor("[classload]", "java.lang.Object", "source:");
+        checkFor("[classunload]", "unloading class");
+
+        //  -Xlog:classloaderdata=trace
+        pb = exec("-Xlog:classloaderdata=trace");
+        checkFor("[classloaderdata]", "create class loader data");
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/runtime/logging/classes/test/Empty.java	Wed Feb 03 11:40:30 2016 -0500
@@ -0,0 +1,5 @@
+package test;
+
+public class Empty {
+public String toString() { return "nothing"; }
+}
--- a/test/runtime/testlibrary/ClassUnloadCommon.java	Tue Feb 02 14:54:05 2016 +0000
+++ b/test/runtime/testlibrary/ClassUnloadCommon.java	Wed Feb 03 11:40:30 2016 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, 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
@@ -21,6 +21,12 @@
  * questions.
  */
 
+
+/*
+ * To use ClassUnloadCommon from a sub-process, see hotspot/test/runtime/logging/ClassLoadUnloadTest.java
+ * for an example.
+ */
+
 import java.io.File;
 import java.net.MalformedURLException;
 import java.net.URL;