8205611: Improve the wording of LinkageErrors to include module and class loader information
authorlfoltan
Mon, 16 Jul 2018 11:34:17 -0400
changeset 51097 bef02342d179
parent 51096 695dff91a997
child 51098 9bad3472ee2c
8205611: Improve the wording of LinkageErrors to include module and class loader information Summary: Clean up the wording of loader constraint violations to include the module and class loader information. Reviewed-by: coleenp, goetz, hseigel
src/hotspot/share/classfile/javaClasses.cpp
src/hotspot/share/classfile/javaClasses.hpp
src/hotspot/share/classfile/systemDictionary.cpp
src/hotspot/share/interpreter/linkResolver.cpp
src/hotspot/share/oops/klassVtable.cpp
test/hotspot/jtreg/runtime/LoaderConstraints/differentLE/Test.java
test/hotspot/jtreg/runtime/LoaderConstraints/duplicateLE/Test.java
test/hotspot/jtreg/runtime/LoaderConstraints/itableLdrConstraint/Test.java
test/hotspot/jtreg/runtime/LoaderConstraints/vtableLdrConstraint/Test.java
--- a/src/hotspot/share/classfile/javaClasses.cpp	Mon Jul 16 09:06:33 2018 -0400
+++ b/src/hotspot/share/classfile/javaClasses.cpp	Mon Jul 16 11:34:17 2018 -0400
@@ -4129,37 +4129,6 @@
   return loader->obj_field(unnamedModule_offset);
 }
 
-// Caller needs ResourceMark.
-const char* java_lang_ClassLoader::describe_external(const oop loader) {
-  ClassLoaderData *cld = ClassLoaderData::class_loader_data(loader);
-  const char* name = cld->loader_name_and_id();
-
-  // bootstrap loader
-  if (loader == NULL) {
-    return name;
-  }
-
-  bool well_known_loader = SystemDictionary::is_system_class_loader(loader) ||
-                           SystemDictionary::is_platform_class_loader(loader);
-
-  stringStream ss;
-  ss.print("%s (instance of %s", name, loader->klass()->external_name());
-  if (!well_known_loader) {
-    oop pl = java_lang_ClassLoader::parent(loader);
-    ClassLoaderData *pl_cld = ClassLoaderData::class_loader_data(pl);
-    const char* parentName = pl_cld->loader_name_and_id();
-    if (pl != NULL) {
-      ss.print(", child of %s %s", parentName, pl->klass()->external_name());
-    } else {
-      // bootstrap loader
-      ss.print(", child of %s", parentName);
-    }
-  }
-  ss.print(")");
-
-  return ss.as_string();
-}
-
 // Support for java_lang_System
 //
 #define SYSTEM_FIELDS_DO(macro) \
--- a/src/hotspot/share/classfile/javaClasses.hpp	Mon Jul 16 09:06:33 2018 -0400
+++ b/src/hotspot/share/classfile/javaClasses.hpp	Mon Jul 16 11:34:17 2018 -0400
@@ -1310,12 +1310,6 @@
   // Debugging
   friend class JavaClasses;
   friend class ClassFileParser; // access to number_of_fake_fields
-
-  // Describe ClassLoader for exceptions, tracing ...
-  // Prints "<name>" (instance of <classname>, child of "<name>" <classname>).
-  // If a classloader has no name, it prints <unnamed> instead. The output
-  // for well known loaders (system/platform) is abbreviated.
-  static const char* describe_external(const oop loader);
 };
 
 
--- a/src/hotspot/share/classfile/systemDictionary.cpp	Mon Jul 16 09:06:33 2018 -0400
+++ b/src/hotspot/share/classfile/systemDictionary.cpp	Mon Jul 16 11:34:17 2018 -0400
@@ -2084,9 +2084,9 @@
       assert(check->is_instance_klass(), "noninstance in systemdictionary");
       if ((defining == true) || (k != check)) {
         throwException = true;
-        ss.print("loader %s", java_lang_ClassLoader::describe_external(class_loader()));
-        ss.print(" attempted duplicate %s definition for %s.",
-                 k->external_kind(), k->external_name());
+        ss.print("loader %s", loader_data->loader_name_and_id());
+        ss.print(" attempted duplicate %s definition for %s. (%s)",
+                 k->external_kind(), k->external_name(), k->class_in_module_of_loader(false, true));
       } else {
         return;
       }
@@ -2100,15 +2100,17 @@
     if (throwException == false) {
       if (constraints()->check_or_update(k, class_loader, name) == false) {
         throwException = true;
-        ss.print("loader constraint violation: loader %s",
-                 java_lang_ClassLoader::describe_external(class_loader()));
+        ss.print("loader constraint violation: loader %s", loader_data->loader_name_and_id());
         ss.print(" wants to load %s %s.",
                  k->external_kind(), k->external_name());
         Klass *existing_klass = constraints()->find_constrained_klass(name, class_loader);
         if (existing_klass->class_loader() != class_loader()) {
-          ss.print(" A different %s with the same name was previously loaded by %s.",
+          ss.print(" A different %s with the same name was previously loaded by %s. (%s)",
                    existing_klass->external_kind(),
-                   java_lang_ClassLoader::describe_external(existing_klass->class_loader()));
+                   existing_klass->class_loader_data()->loader_name_and_id(),
+                   existing_klass->class_in_module_of_loader(false, true));
+        } else {
+          ss.print(" (%s)", k->class_in_module_of_loader(false, true));
         }
       }
     }
--- a/src/hotspot/share/interpreter/linkResolver.cpp	Mon Jul 16 09:06:33 2018 -0400
+++ b/src/hotspot/share/interpreter/linkResolver.cpp	Mon Jul 16 11:34:17 2018 -0400
@@ -669,23 +669,28 @@
     SystemDictionary::check_signature_loaders(link_info.signature(), current_loader,
                                               resolved_loader, true, CHECK);
   if (failed_type_symbol != NULL) {
-    const char* msg = "loader constraint violation: when resolving %s"
-      " \"%s\" the class loader %s of the current class, %s,"
-      " and the class loader %s for the method's defining class, %s, have"
-      " different Class objects for the type %s used in the signature";
-    char* sig = link_info.method_string();
-    const char* loader1_name = java_lang_ClassLoader::describe_external(current_loader());
-    char* current = link_info.current_klass()->name()->as_C_string();
-    const char* loader2_name = java_lang_ClassLoader::describe_external(resolved_loader());
-    char* target = resolved_method->method_holder()->name()->as_C_string();
-    char* failed_type_name = failed_type_symbol->as_C_string();
-    size_t buflen = strlen(msg) + strlen(sig) + strlen(loader1_name) +
-      strlen(current) + strlen(loader2_name) + strlen(target) +
-      strlen(failed_type_name) + strlen(method_type) + 1;
-    char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen);
-    jio_snprintf(buf, buflen, msg, method_type, sig, loader1_name, current, loader2_name,
-                 target, failed_type_name);
-    THROW_MSG(vmSymbols::java_lang_LinkageError(), buf);
+    Klass* current_class = link_info.current_klass();
+    ClassLoaderData* current_loader_data = current_class->class_loader_data();
+    assert(current_loader_data != NULL, "current class has no class loader data");
+    Klass* resolved_method_class = resolved_method->method_holder();
+    ClassLoaderData* target_loader_data = resolved_method_class->class_loader_data();
+    assert(target_loader_data != NULL, "resolved method's class has no class loader data");
+
+    stringStream ss;
+    ss.print("loader constraint violation: when resolving %s"
+             " \"%s\" the class loader %s of the current class, %s,"
+             " and the class loader %s for the method's defining class, %s, have"
+             " different Class objects for the type %s used in the signature (%s; %s)",
+             method_type,
+             link_info.method_string(),
+             current_loader_data->loader_name_and_id(),
+             current_class->name()->as_C_string(),
+             target_loader_data->loader_name_and_id(),
+             resolved_method_class->name()->as_C_string(),
+             failed_type_symbol->as_C_string(),
+             current_class->class_in_module_of_loader(false, true),
+             resolved_method_class->class_in_module_of_loader(false, true));
+    THROW_MSG(vmSymbols::java_lang_LinkageError(), ss.as_string());
   }
 }
 
@@ -702,23 +707,23 @@
                                               false,
                                               CHECK);
   if (failed_type_symbol != NULL) {
-    const char* msg = "loader constraint violation: when resolving field"
-      " \"%s\" of type %s, the class loader %s of the current class, "
-      "%s, and the class loader %s for the field's defining "
-      "type, %s, have different Class objects for type %s";
-    const char* field_name = field->as_C_string();
-    const char* loader1_name = java_lang_ClassLoader::describe_external(ref_loader());
-    const char* sel = sel_klass->external_name();
-    const char* loader2_name = java_lang_ClassLoader::describe_external(sel_loader());
+    stringStream ss;
     const char* failed_type_name = failed_type_symbol->as_klass_external_name();
-    const char* curr_klass_name = current_klass->external_name();
-    size_t buflen = strlen(msg) + strlen(field_name) + 2 * strlen(failed_type_name) +
-                    strlen(loader1_name) + strlen(curr_klass_name) +
-                    strlen(loader2_name) + strlen(sel) + 1;
-    char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen);
-    jio_snprintf(buf, buflen, msg, field_name, failed_type_name, loader1_name,
-                 curr_klass_name, loader2_name, sel, failed_type_name);
-    THROW_MSG(vmSymbols::java_lang_LinkageError(), buf);
+
+    ss.print("loader constraint violation: when resolving field"
+             " \"%s\" of type %s, the class loader %s of the current class, "
+             "%s, and the class loader %s for the field's defining "
+             "type, %s, have different Class objects for type %s (%s; %s)",
+             field->as_C_string(),
+             failed_type_name,
+             current_klass->class_loader_data()->loader_name_and_id(),
+             current_klass->external_name(),
+             sel_klass->class_loader_data()->loader_name_and_id(),
+             sel_klass->external_name(),
+             failed_type_name,
+             current_klass->class_in_module_of_loader(false, true),
+             sel_klass->class_in_module_of_loader(false, true));
+    THROW_MSG(vmSymbols::java_lang_LinkageError(), ss.as_string());
   }
 }
 
--- a/src/hotspot/share/oops/klassVtable.cpp	Mon Jul 16 09:06:33 2018 -0400
+++ b/src/hotspot/share/oops/klassVtable.cpp	Mon Jul 16 11:34:17 2018 -0400
@@ -506,24 +506,21 @@
                                                         super_loader, true,
                                                         CHECK_(false));
             if (failed_type_symbol != NULL) {
-              const char* msg = "loader constraint violation for class %s: when selecting "
-                "overriding method %s the class loader %s of the "
-                "selected method's type %s, and the class loader %s for its super "
-                "type %s have different Class objects for the type %s used in the signature";
-              const char* curr_class = klass->external_name();
-              const char* method = target_method()->name_and_sig_as_C_string();
-              const char* loader1 = java_lang_ClassLoader::describe_external(target_loader());
-              const char* sel_class = target_klass->external_name();
-              const char* loader2 = java_lang_ClassLoader::describe_external(super_loader());
-              const char* super_class = super_klass->external_name();
-              const char* failed_type_name = failed_type_symbol->as_klass_external_name();
-              size_t buflen = strlen(msg) + strlen(curr_class) + strlen(method) +
-                strlen(loader1) + strlen(sel_class) + strlen(loader2) +
-                strlen(super_class) + strlen(failed_type_name);
-              char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen);
-              jio_snprintf(buf, buflen, msg, curr_class, method, loader1, sel_class, loader2,
-                           super_class, failed_type_name);
-              THROW_MSG_(vmSymbols::java_lang_LinkageError(), buf, false);
+              stringStream ss;
+              ss.print("loader constraint violation for class %s: when selecting "
+                       "overriding method %s the class loader %s of the "
+                       "selected method's type %s, and the class loader %s for its super "
+                       "type %s have different Class objects for the type %s used in the signature (%s; %s)",
+                       klass->external_name(),
+                       target_method()->name_and_sig_as_C_string(),
+                       target_klass->class_loader_data()->loader_name_and_id(),
+                       target_klass->external_name(),
+                       super_klass->class_loader_data()->loader_name_and_id(),
+                       super_klass->external_name(),
+                       failed_type_symbol->as_klass_external_name(),
+                       target_klass->class_in_module_of_loader(false, true),
+                       super_klass->class_in_module_of_loader(false, true));
+              THROW_MSG_(vmSymbols::java_lang_LinkageError(), ss.as_string(), false);
             }
           }
         }
@@ -1242,25 +1239,22 @@
                                                       interface_loader,
                                                       true, CHECK);
           if (failed_type_symbol != NULL) {
-            const char* msg = "loader constraint violation in interface itable"
-              " initialization for class %s: when selecting method %s the"
-              " class loader %s for super interface %s, and the class"
-              " loader %s of the selected method's type, %s have"
-              " different Class objects for the type %s used in the signature";
-            const char* current = _klass->external_name();
-            const char* sig = m->name_and_sig_as_C_string();
-            const char* loader1 = java_lang_ClassLoader::describe_external(interface_loader());
-            const char* iface = InstanceKlass::cast(interf)->external_name();
-            const char* loader2 = java_lang_ClassLoader::describe_external(method_holder_loader());
-            const char* mclass = target()->method_holder()->external_name();
-            const char* failed_type_name = failed_type_symbol->as_klass_external_name();
-            size_t buflen = strlen(msg) + strlen(current) + strlen(sig) +
-              strlen(loader1) + strlen(iface) + strlen(loader2) + strlen(mclass) +
-              strlen(failed_type_name);
-            char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen);
-            jio_snprintf(buf, buflen, msg, current, sig, loader1, iface,
-                         loader2, mclass, failed_type_name);
-            THROW_MSG(vmSymbols::java_lang_LinkageError(), buf);
+            stringStream ss;
+            ss.print("loader constraint violation in interface itable"
+                     " initialization for class %s: when selecting method %s the"
+                     " class loader %s for super interface %s, and the class"
+                     " loader %s of the selected method's type, %s have"
+                     " different Class objects for the type %s used in the signature (%s; %s)",
+                     _klass->external_name(),
+                     m->name_and_sig_as_C_string(),
+                     interf->class_loader_data()->loader_name_and_id(),
+                     interf->external_name(),
+                     target()->method_holder()->class_loader_data()->loader_name_and_id(),
+                     target()->method_holder()->external_name(),
+                     failed_type_symbol->as_klass_external_name(),
+                     interf->class_in_module_of_loader(false, true),
+                     target()->method_holder()->class_in_module_of_loader(false, true));
+            THROW_MSG(vmSymbols::java_lang_LinkageError(), ss.as_string());
           }
         }
       }
--- a/test/hotspot/jtreg/runtime/LoaderConstraints/differentLE/Test.java	Mon Jul 16 09:06:33 2018 -0400
+++ b/test/hotspot/jtreg/runtime/LoaderConstraints/differentLE/Test.java	Mon Jul 16 11:34:17 2018 -0400
@@ -78,11 +78,9 @@
     // Break the expectedErrorMessage into 2 pieces since the loader name will include
     // its identity hash and can not be compared against.
     static String expectedErrorMessage_part1 = "loader constraint violation: loader PreemptingClassLoader @";
-    static String expectedErrorMessage_part2 = " (instance of PreemptingClassLoader, " +
-        "child of 'app' jdk.internal.loader.ClassLoaders$AppClassLoader) wants to load " +
-        "class test.D_ambgs. A different class with the same name was previously loaded " +
-        "by 'app' (instance of jdk.internal.loader.ClassLoaders$AppClassLoader).";
-
+    static String expectedErrorMessage_part2 = " wants to load class test.D_ambgs. A different class " +
+                                               "with the same name was previously loaded by 'app'. " +
+                                               "(test.D_ambgs is in unnamed module of loader 'app')";
     public static void test_access() throws Exception {
         try {
             // Make a Class 'D_ambgs' under the default loader.
@@ -118,4 +116,3 @@
         test_access();
     }
 }
-
--- a/test/hotspot/jtreg/runtime/LoaderConstraints/duplicateLE/Test.java	Mon Jul 16 09:06:33 2018 -0400
+++ b/test/hotspot/jtreg/runtime/LoaderConstraints/duplicateLE/Test.java	Mon Jul 16 11:34:17 2018 -0400
@@ -40,26 +40,21 @@
     // Break each expectedErrorMessage into 2 parts due to the class loader name containing
     // the unique @<id> identity hash which cannot be compared against.
     static String expectedErrorMessage1_part1 = "loader PreemptingClassLoader @";
-    static String expectedErrorMessage1_part2 =
-        " (instance of PreemptingClassLoader, " +
-        "child of 'app' jdk.internal.loader.ClassLoaders$AppClassLoader) " +
-        "attempted duplicate class definition for test.Foo.";
+    static String expectedErrorMessage1_part2 = " attempted duplicate class definition for test.Foo. (test.Foo is in unnamed module of loader PreemptingClassLoader @";
+    static String expectedErrorMessage1_part3 = ", parent loader 'app')";
 
     // Check that all names have external formatting ('.' and not '/' in package names).
     // Check for name and parent of class loader.
     static String expectedErrorMessage2_part1 = "loader 'DuplicateLE_Test_Loader' @";
-    static String expectedErrorMessage2_part2 =
-        " (instance of PreemptingClassLoader, " +
-        "child of 'app' jdk.internal.loader.ClassLoaders$AppClassLoader) " +
-        "attempted duplicate class definition for test.Foo.";
+    static String expectedErrorMessage2_part2 = " attempted duplicate class definition for test.Foo. (test.Foo is in unnamed module of loader 'DuplicateLE_Test_Loader' @";
+    static String expectedErrorMessage2_part3 = ", parent loader 'app')";
 
     // Check that all names have external formatting ('.' and not '/' in package names).
     // Check for name and parent of class loader. Type should be mentioned as 'interface'.
     static String expectedErrorMessage3_part1 = "loader 'DuplicateLE_Test_Loader_IF' @";
-    static String expectedErrorMessage3_part2 =
-        " (instance of PreemptingClassLoader, " +
-        "child of 'app' jdk.internal.loader.ClassLoaders$AppClassLoader) " +
-        "attempted duplicate interface definition for test.J.";
+    static String expectedErrorMessage3_part2 = " attempted duplicate interface definition for test.J. (test.J is in unnamed module of loader 'DuplicateLE_Test_Loader_IF' @";
+    static String expectedErrorMessage3_part3 = ", parent loader 'app')";
+
 
     // Test that the error message is correct when a loader constraint error is
     // detected during vtable creation.
@@ -68,8 +63,11 @@
     // overrides "J.m()LFoo;".  But, Task's class Foo and super type J's class Foo
     // are different.  So, a LinkageError exception should be thrown because the
     // loader constraint check will fail.
-    public static void test(String loaderName, String expectedErrorMessage_part1,
-                            String expectedErrorMessage_part2, String testType) throws Exception {
+    public static void test(String loaderName,
+                            String expectedErrorMessage_part1,
+                            String expectedErrorMessage_part2,
+                            String expectedErrorMessage_part3,
+                            String testType) throws Exception {
         String[] classNames = {testType};
         ClassLoader l = new PreemptingClassLoader(loaderName, classNames, false);
         l.loadClass(testType);
@@ -79,7 +77,8 @@
         } catch (LinkageError e) {
             String errorMsg = e.getMessage();
             if (!errorMsg.contains(expectedErrorMessage_part1) ||
-                !errorMsg.contains(expectedErrorMessage_part2)) {
+                !errorMsg.contains(expectedErrorMessage_part2) ||
+                !errorMsg.contains(expectedErrorMessage_part3)) {
                 System.out.println("Expected: " + expectedErrorMessage_part1 + "<id>" + expectedErrorMessage_part2 + "\n" +
                                    "but got:  " + errorMsg);
                 throw new RuntimeException("Wrong LinkageError exception thrown: " + errorMsg);
@@ -89,9 +88,11 @@
     }
 
     public static void main(String args[]) throws Exception {
-        test(null, expectedErrorMessage1_part1, expectedErrorMessage1_part2, "test.Foo");
-        test("DuplicateLE_Test_Loader", expectedErrorMessage2_part1, expectedErrorMessage2_part2, "test.Foo");
-        test("DuplicateLE_Test_Loader_IF", expectedErrorMessage3_part1, expectedErrorMessage3_part2, "test.J");
+        test(null, expectedErrorMessage1_part1, expectedErrorMessage1_part2,
+             expectedErrorMessage1_part3, "test.Foo");
+        test("DuplicateLE_Test_Loader", expectedErrorMessage2_part1, expectedErrorMessage2_part2,
+             expectedErrorMessage2_part3, "test.Foo");
+        test("DuplicateLE_Test_Loader_IF", expectedErrorMessage3_part1, expectedErrorMessage3_part2,
+             expectedErrorMessage3_part3, "test.J");
     }
 }
-
--- a/test/hotspot/jtreg/runtime/LoaderConstraints/itableLdrConstraint/Test.java	Mon Jul 16 09:06:33 2018 -0400
+++ b/test/hotspot/jtreg/runtime/LoaderConstraints/itableLdrConstraint/Test.java	Mon Jul 16 11:34:17 2018 -0400
@@ -35,31 +35,25 @@
 
 public class Test {
 
-    // Break expected error messages into 2 parts since the loader name includes its identity
+    // Break expected error messages into 3 parts since the loader name includes its identity
     // hash which is unique and can't be compared against.
-    static String expectedErrorMessage1_part1 =
-        "loader constraint violation in interface itable initialization for class test.C: " +
-        "when selecting method test.I.m()Ltest/Foo; " +
-        "the class loader PreemptingClassLoader @";
-    static String expectedErrorMessage1_part2 =
-        " (instance of PreemptingClassLoader, " +
-        "child of 'app' jdk.internal.loader.ClassLoaders$AppClassLoader) " +
-        "for super interface test.I, and the class loader 'app' " +
-        "(instance of jdk.internal.loader.ClassLoaders$AppClassLoader) " +
-        "of the selected method's type, test.J have different Class objects " +
-        "for the type test.Foo used in the signature";
+    static String expectedErrorMessage1_part1 = "loader constraint violation in interface itable initialization for " +
+                                                "class test.C: when selecting method test.I.m()Ltest/Foo; the class loader " +
+                                                "PreemptingClassLoader @";
+    static String expectedErrorMessage1_part2 = " for super interface test.I, and the class loader 'app' of the " +
+                                                "selected method's type, test.J have different Class objects for the " +
+                                                "type test.Foo used in the signature (test.I is in unnamed module of loader " +
+                                                "PreemptingClassLoader @";
+    static String expectedErrorMessage1_part3 = ", parent loader 'app'; test.J is in unnamed module of loader 'app')";
 
-    static String expectedErrorMessage2_part1 =
-        "loader constraint violation in interface itable initialization for class test.C: " +
-        "when selecting method test.I.m()Ltest/Foo; " +
-        "the class loader 'ItableLdrCnstrnt_Test_Loader' @";
-    static String expectedErrorMessage2_part2 =
-        " (instance of PreemptingClassLoader, " +
-        "child of 'app' jdk.internal.loader.ClassLoaders$AppClassLoader) " +
-        "for super interface test.I, and the class loader 'app' " +
-        "(instance of jdk.internal.loader.ClassLoaders$AppClassLoader) " +
-        "of the selected method's type, test.J have different Class objects " +
-        "for the type test.Foo used in the signature";
+    static String expectedErrorMessage2_part1 = "loader constraint violation in interface itable initialization for " +
+                                                "class test.C: when selecting method test.I.m()Ltest/Foo; the class loader " +
+                                                "'ItableLdrCnstrnt_Test_Loader' @";
+    static String expectedErrorMessage2_part2 = " for super interface test.I, and the class loader 'app' of the " +
+                                                "selected method's type, test.J have different Class objects for the " +
+                                                "type test.Foo used in the signature (test.I is in unnamed module of loader " +
+                                                "'ItableLdrCnstrnt_Test_Loader' @";
+    static String expectedErrorMessage2_part3 = ", parent loader 'app'; test.J is in unnamed module of loader 'app')";
 
     // Test that the error message is correct when a loader constraint error is
     // detected during itable creation.
@@ -71,7 +65,8 @@
     // exception should be thrown because the loader constraint check will fail.
     public static void test(String loaderName,
                             String expectedErrorMessage_part1,
-                            String expectedErrorMessage_part2) throws Exception {
+                            String expectedErrorMessage_part2,
+                            String expectedErrorMessage_part3) throws Exception {
         Class<?> c = test.Foo.class; // Forces standard class loader to load Foo.
         String[] classNames = {"test.Task", "test.Foo", "test.C", "test.I"};
         ClassLoader l = new PreemptingClassLoader(loaderName, classNames);
@@ -82,7 +77,8 @@
         } catch (LinkageError e) {
             String errorMsg = e.getMessage();
             if (!errorMsg.contains(expectedErrorMessage_part1) ||
-                !errorMsg.contains(expectedErrorMessage_part2)) {
+                !errorMsg.contains(expectedErrorMessage_part2) ||
+                !errorMsg.contains(expectedErrorMessage_part3)) {
                 System.out.println("Expected: " + expectedErrorMessage_part1 + "<id>" + expectedErrorMessage_part2 + "\n" +
                                    "but got:  " + errorMsg);
                 throw new RuntimeException("Wrong LinkageError exception thrown: " + errorMsg);
@@ -92,7 +88,7 @@
     }
 
     public static void main(String... args) throws Exception {
-        test(null, expectedErrorMessage1_part1, expectedErrorMessage1_part2);
-        test("ItableLdrCnstrnt_Test_Loader", expectedErrorMessage2_part1, expectedErrorMessage2_part2);
+        test(null, expectedErrorMessage1_part1, expectedErrorMessage1_part2, expectedErrorMessage1_part3);
+        test("ItableLdrCnstrnt_Test_Loader", expectedErrorMessage2_part1, expectedErrorMessage2_part2, expectedErrorMessage2_part3);
     }
 }
--- a/test/hotspot/jtreg/runtime/LoaderConstraints/vtableLdrConstraint/Test.java	Mon Jul 16 09:06:33 2018 -0400
+++ b/test/hotspot/jtreg/runtime/LoaderConstraints/vtableLdrConstraint/Test.java	Mon Jul 16 11:34:17 2018 -0400
@@ -35,31 +35,25 @@
 
 public class Test {
 
-    // Break expected error messages into 2 parts since the loader name includes its identity
+    // Break expected error messages into 3 parts since the loader name includes its identity
     // hash which is unique and can't be compared against.
-    static String expectedErrorMessage1_part1 =
-        "loader constraint violation for class test.Task: " +
-        "when selecting overriding method test.Task.m()Ltest/Foo; " +
-        "the class loader PreemptingClassLoader @";
-    static String expectedErrorMessage1_part2 =
-        " (instance of PreemptingClassLoader, " +
-        "child of 'app' jdk.internal.loader.ClassLoaders$AppClassLoader) " +
-        "of the selected method's type test.Task, " +
-        "and the class loader 'app' (instance of jdk.internal.loader.ClassLoaders$AppClassLoader) " +
-        "for its super type test.J " +
-        "have different Class objects for the type test.Foo used in the signature";
+    static String expectedErrorMessage1_part1 = "loader constraint violation for class test.Task: when " +
+                                                "selecting overriding method test.Task.m()Ltest/Foo; the " +
+                                                "class loader PreemptingClassLoader @";
+    static String expectedErrorMessage1_part2 = " of the selected method's type test.Task, and the class " +
+                                                "loader 'app' for its super type test.J have different Class objects " +
+                                                "for the type test.Foo used in the signature (test.Task is in unnamed " +
+                                                "module of loader PreemptingClassLoader @";
+    static String expectedErrorMessage1_part3 = ", parent loader 'app'; test.J is in unnamed module of loader 'app')";
 
-    static String expectedErrorMessage2_part1 =
-        "loader constraint violation for class test.Task: " +
-        "when selecting overriding method test.Task.m()Ltest/Foo; " +
-        "the class loader 'VtableLdrCnstrnt_Test_Loader' @";
-    static String expectedErrorMessage2_part2 =
-        " (instance of PreemptingClassLoader, " +
-        "child of 'app' jdk.internal.loader.ClassLoaders$AppClassLoader) " +
-        "of the selected method's type test.Task, " +
-        "and the class loader 'app' (instance of jdk.internal.loader.ClassLoaders$AppClassLoader) " +
-        "for its super type test.J " +
-        "have different Class objects for the type test.Foo used in the signature";
+    static String expectedErrorMessage2_part1 = "loader constraint violation for class test.Task: when " +
+                                                "selecting overriding method test.Task.m()Ltest/Foo; the " +
+                                                "class loader 'VtableLdrCnstrnt_Test_Loader' @";
+    static String expectedErrorMessage2_part2 = " of the selected method's type test.Task, and the class " +
+                                                "loader 'app' for its super type test.J have different Class objects " +
+                                                "for the type test.Foo used in the signature (test.Task is in unnamed " +
+                                                "module of loader 'VtableLdrCnstrnt_Test_Loader' @";
+    static String expectedErrorMessage2_part3 = ", parent loader 'app'; test.J is in unnamed module of loader 'app')";
 
     // Test that the error message is correct when a loader constraint error is
     // detected during vtable creation.
@@ -70,7 +64,8 @@
     // loader constraint check will fail.
     public static void test(String loaderName,
                             String expectedErrorMessage_part1,
-                            String expectedErrorMessage_part2) throws Exception {
+                            String expectedErrorMessage_part2,
+                            String expectedErrorMessage_part3) throws Exception {
         Class<?> c = test.Foo.class; // Forces standard class loader to load Foo.
         String[] classNames = {"test.Task", "test.Foo", "test.I"};
         ClassLoader l = new PreemptingClassLoader(loaderName, classNames);
@@ -81,7 +76,8 @@
         } catch (LinkageError e) {
             String errorMsg = e.getMessage();
             if (!errorMsg.contains(expectedErrorMessage_part1) ||
-                !errorMsg.contains(expectedErrorMessage_part2)) {
+                !errorMsg.contains(expectedErrorMessage_part2) ||
+                !errorMsg.contains(expectedErrorMessage_part3)) {
                 System.out.println("Expected: " + expectedErrorMessage_part1 + "<id>" + expectedErrorMessage_part2 + "\n" +
                                    "but got:  " + errorMsg);
                 throw new RuntimeException("Wrong LinkageError exception thrown: " + errorMsg);
@@ -91,8 +87,9 @@
     }
 
     public static void main(String args[]) throws Exception {
-        test(null, expectedErrorMessage1_part1, expectedErrorMessage1_part2);
-        test("VtableLdrCnstrnt_Test_Loader", expectedErrorMessage2_part1, expectedErrorMessage2_part2);
+        test(null, expectedErrorMessage1_part1,
+             expectedErrorMessage1_part2, expectedErrorMessage1_part3);
+        test("VtableLdrCnstrnt_Test_Loader", expectedErrorMessage2_part1,
+             expectedErrorMessage2_part2, expectedErrorMessage2_part3);
     }
 }
-