8169559: Add class loader names to relevant VM messages
Summary: Added new method class_in_module_of_loader to provide a standard format for class information within error messages.
Reviewed-by: goetz, hseigel, mchung
--- a/src/hotspot/share/classfile/classFileParser.cpp Mon Jun 25 20:36:06 2018 +0530
+++ b/src/hotspot/share/classfile/classFileParser.cpp Mon Jun 25 11:33:11 2018 -0400
@@ -955,9 +955,10 @@
if (!interf->is_interface()) {
THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(),
- err_msg("Class %s can not implement %s, because it is not an interface",
+ err_msg("class %s can not implement %s, because it is not an interface (%s)",
_class_name->as_klass_external_name(),
- interf->class_loader_and_module_name()));
+ interf->external_name(),
+ interf->class_in_module_of_loader()));
}
if (InstanceKlass::cast(interf)->has_nonstatic_concrete_methods()) {
--- a/src/hotspot/share/classfile/moduleEntry.hpp Mon Jun 25 20:36:06 2018 +0530
+++ b/src/hotspot/share/classfile/moduleEntry.hpp Mon Jun 25 11:33:11 2018 -0400
@@ -40,10 +40,12 @@
#include "jfr/support/jfrTraceIdExtension.hpp"
#endif
-#define UNNAMED_MODULE "Unnamed Module"
+#define UNNAMED_MODULE "unnamed module"
+#define UNNAMED_MODULE_LEN 14
#define JAVAPKG "java"
#define JAVAPKG_LEN 4
#define JAVA_BASE_NAME "java.base"
+#define JAVA_BASE_NAME_LEN 9
class ModuleClosure;
--- a/src/hotspot/share/interpreter/linkResolver.cpp Mon Jun 25 20:36:06 2018 +0530
+++ b/src/hotspot/share/interpreter/linkResolver.cpp Mon Jun 25 11:33:11 2018 -0400
@@ -592,14 +592,18 @@
// from nest-host resolution, have been allowed to propagate.
if (!can_access) {
ResourceMark rm(THREAD);
+ bool same_module = (sel_klass->module() == ref_klass->module());
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_IllegalAccessError(),
- "tried to access method %s.%s%s from class %s",
+ "class %s tried to access method %s.%s%s (%s%s%s)",
+ ref_klass->external_name(),
sel_klass->external_name(),
sel_method->name()->as_C_string(),
sel_method->signature()->as_C_string(),
- ref_klass->external_name()
+ (same_module) ? ref_klass->joint_in_module_of_loader(sel_klass) : ref_klass->class_in_module_of_loader(),
+ (same_module) ? "" : "; ",
+ (same_module) ? "" : sel_klass->class_in_module_of_loader()
);
return;
}
--- a/src/hotspot/share/oops/instanceKlass.cpp Mon Jun 25 20:36:06 2018 +0530
+++ b/src/hotspot/share/oops/instanceKlass.cpp Mon Jun 25 11:33:11 2018 -0400
@@ -2850,9 +2850,14 @@
if (cnt >= nof_interfaces) {
ResourceMark rm(THREAD);
stringStream ss;
+ bool same_module = (module() == holder->module());
ss.print("Receiver class %s does not implement "
- "the interface %s defining the method to be called",
- class_loader_and_module_name(), holder->class_loader_and_module_name());
+ "the interface %s defining the method to be called "
+ "(%s%s%s)",
+ external_name(), holder->external_name(),
+ (same_module) ? joint_in_module_of_loader(holder) : class_in_module_of_loader(),
+ (same_module) ? "" : "; ",
+ (same_module) ? "" : holder->class_in_module_of_loader());
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string());
}
--- a/src/hotspot/share/oops/klass.cpp Mon Jun 25 20:36:06 2018 +0530
+++ b/src/hotspot/share/oops/klass.cpp Mon Jun 25 11:33:11 2018 -0400
@@ -774,80 +774,124 @@
#endif // PRODUCT
-// The caller of class_loader_and_module_name() (or one of its callers)
-// must use a ResourceMark in order to correctly free the result.
-const char* Klass::class_loader_and_module_name() const {
- const char* delim = "/";
- size_t delim_len = strlen(delim);
-
- const char* fqn = external_name();
- // Length of message to return; always include FQN
- size_t msglen = strlen(fqn) + 1;
-
- bool has_cl_name = false;
- bool has_mod_name = false;
- bool has_version = false;
+// Caller needs ResourceMark
+// joint_in_module_of_loader provides an optimization if 2 classes are in
+// the same module to succinctly print out relevant information about their
+// module name and class loader's name_and_id for error messages.
+// Format:
+// <fully-qualified-external-class-name1> and <fully-qualified-external-class-name2>
+// are in module <module-name>[@<version>]
+// of loader <loader-name_and_id>[, parent loader <parent-loader-name_and_id>]
+const char* Klass::joint_in_module_of_loader(const Klass* class2, bool include_parent_loader) const {
+ assert(module() == class2->module(), "classes do not have the same module");
+ const char* class1_name = external_name();
+ size_t len = strlen(class1_name) + 1;
- // Use class loader name, if exists and not builtin
- const char* class_loader_name = "";
- ClassLoaderData* cld = class_loader_data();
- assert(cld != NULL, "class_loader_data should not be NULL");
- if (!cld->is_builtin_class_loader_data()) {
- // If not builtin, look for name
- oop loader = class_loader();
- if (loader != NULL) {
- oop class_loader_name_oop = java_lang_ClassLoader::name(loader);
- if (class_loader_name_oop != NULL) {
- class_loader_name = java_lang_String::as_utf8_string(class_loader_name_oop);
- if (class_loader_name != NULL && class_loader_name[0] != '\0') {
- has_cl_name = true;
- msglen += strlen(class_loader_name) + delim_len;
- }
- }
- }
+ const char* class2_description = class2->class_in_module_of_loader(true, include_parent_loader);
+ len += strlen(class2_description);
+
+ len += strlen(" and ");
+
+ char* joint_description = NEW_RESOURCE_ARRAY_RETURN_NULL(char, len);
+
+ // Just return the FQN if error when allocating string
+ if (joint_description == NULL) {
+ return class1_name;
}
+ jio_snprintf(joint_description, len, "%s and %s",
+ class1_name,
+ class2_description);
+
+ return joint_description;
+}
+
+// Caller needs ResourceMark
+// class_in_module_of_loader provides a standard way to include
+// relevant information about a class, such as its module name as
+// well as its class loader's name_and_id, in error messages and logging.
+// Format:
+// <fully-qualified-external-class-name> is in module <module-name>[@<version>]
+// of loader <loader-name_and_id>[, parent loader <parent-loader-name_and_id>]
+const char* Klass::class_in_module_of_loader(bool use_are, bool include_parent_loader) const {
+ // 1. fully qualified external name of class
+ const char* klass_name = external_name();
+ size_t len = strlen(klass_name) + 1;
+
+ // 2. module name + @version
const char* module_name = "";
const char* version = "";
+ bool has_version = false;
+ bool module_is_named = false;
+ const char* module_name_phrase = "";
const Klass* bottom_klass = is_objArray_klass() ?
- ObjArrayKlass::cast(this)->bottom_klass() : this;
+ ObjArrayKlass::cast(this)->bottom_klass() : this;
if (bottom_klass->is_instance_klass()) {
ModuleEntry* module = InstanceKlass::cast(bottom_klass)->module();
- // Use module name, if exists
if (module->is_named()) {
- has_mod_name = true;
+ module_is_named = true;
+ module_name_phrase = "module ";
module_name = module->name()->as_C_string();
- msglen += strlen(module_name);
+ len += strlen(module_name);
// Use version if exists and is not a jdk module
if (module->should_show_version()) {
has_version = true;
version = module->version()->as_C_string();
- msglen += strlen(version) + 1; // +1 for "@"
+ // Include stlen(version) + 1 for the "@"
+ len += strlen(version) + 1;
}
+ } else {
+ module_name = UNNAMED_MODULE;
+ len += UNNAMED_MODULE_LEN;
}
} else {
- // klass is an array of primitives, so its module is java.base
+ // klass is an array of primitives, module is java.base
+ module_is_named = true;
+ module_name_phrase = "module ";
module_name = JAVA_BASE_NAME;
- }
-
- if (has_cl_name || has_mod_name) {
- msglen += delim_len;
+ len += JAVA_BASE_NAME_LEN;
}
- char* message = NEW_RESOURCE_ARRAY_RETURN_NULL(char, msglen);
+ // 3. class loader's name_and_id
+ ClassLoaderData* cld = class_loader_data();
+ assert(cld != NULL, "class_loader_data should not be null");
+ const char* loader_name_and_id = cld->loader_name_and_id();
+ len += strlen(loader_name_and_id);
- // Just return the FQN if error in allocating string
- if (message == NULL) {
- return fqn;
+ // 4. include parent loader information
+ const char* parent_loader_phrase = "";
+ const char* parent_loader_name_and_id = "";
+ if (include_parent_loader &&
+ !cld->is_builtin_class_loader_data()) {
+ oop parent_loader = java_lang_ClassLoader::parent(class_loader());
+ ClassLoaderData *parent_cld = ClassLoaderData::class_loader_data(parent_loader);
+ assert(parent_cld != NULL, "parent's class loader data should not be null");
+ parent_loader_name_and_id = parent_cld->loader_name_and_id();
+ parent_loader_phrase = ", parent loader ";
+ len += strlen(parent_loader_phrase) + strlen(parent_loader_name_and_id);
}
- jio_snprintf(message, msglen, "%s%s%s%s%s%s%s",
- class_loader_name,
- (has_cl_name) ? delim : "",
- (has_mod_name) ? module_name : "",
+ // Start to construct final full class description string
+ len += ((use_are) ? strlen(" are in ") : strlen(" is in "));
+ len += strlen(module_name_phrase) + strlen(" of loader ");
+
+ char* class_description = NEW_RESOURCE_ARRAY_RETURN_NULL(char, len);
+
+ // Just return the FQN if error when allocating string
+ if (class_description == NULL) {
+ return klass_name;
+ }
+
+ jio_snprintf(class_description, len, "%s %s in %s%s%s%s of loader %s%s%s",
+ klass_name,
+ (use_are) ? "are" : "is",
+ module_name_phrase,
+ module_name,
(has_version) ? "@" : "",
(has_version) ? version : "",
- (has_cl_name || has_mod_name) ? delim : "",
- fqn);
- return message;
+ loader_name_and_id,
+ parent_loader_phrase,
+ parent_loader_name_and_id);
+
+ return class_description;
}
--- a/src/hotspot/share/oops/klass.hpp Mon Jun 25 20:36:06 2018 +0530
+++ b/src/hotspot/share/oops/klass.hpp Mon Jun 25 11:33:11 2018 -0400
@@ -560,7 +560,8 @@
// and the package separators as '/'.
virtual const char* signature_name() const;
- const char* class_loader_and_module_name() const;
+ const char* joint_in_module_of_loader(const Klass* class2, bool include_parent_loader = false) const;
+ const char* class_in_module_of_loader(bool use_are = false, bool include_parent_loader = false) const;
// Returns "interface", "abstract class" or "class".
const char* external_kind() const;
--- a/src/hotspot/share/runtime/sharedRuntime.cpp Mon Jun 25 20:36:06 2018 +0530
+++ b/src/hotspot/share/runtime/sharedRuntime.cpp Mon Jun 25 11:33:11 2018 -0400
@@ -1959,14 +1959,27 @@
// must use a ResourceMark in order to correctly free the result.
char* SharedRuntime::generate_class_cast_message(
Klass* caster_klass, Klass* target_klass, Symbol* target_klass_name) {
-
- const char* caster_name = caster_klass->class_loader_and_module_name();
+ const char* caster_name = caster_klass->external_name();
assert(target_klass != NULL || target_klass_name != NULL, "one must be provided");
const char* target_name = target_klass == NULL ? target_klass_name->as_C_string() :
- target_klass->class_loader_and_module_name();
-
- size_t msglen = strlen(caster_name) + strlen(" cannot be cast to ") + strlen(target_name) + 1;
+ target_klass->external_name();
+
+ size_t msglen = strlen(caster_name) + strlen("class ") + strlen(" cannot be cast to class ") + strlen(target_name) + 1;
+
+ const char* caster_klass_description = "";
+ const char* target_klass_description = "";
+ const char* klass_separator = "";
+ if (target_klass != NULL && caster_klass->module() == target_klass->module()) {
+ caster_klass_description = caster_klass->joint_in_module_of_loader(target_klass);
+ } else {
+ caster_klass_description = caster_klass->class_in_module_of_loader();
+ target_klass_description = (target_klass != NULL) ? target_klass->class_in_module_of_loader() : "";
+ klass_separator = (target_klass != NULL) ? "; " : "";
+ }
+
+ // add 3 for parenthesis and preceeding space
+ msglen += strlen(caster_klass_description) + strlen(target_klass_description) + strlen(klass_separator) + 3;
char* message = NEW_RESOURCE_ARRAY_RETURN_NULL(char, msglen);
if (message == NULL) {
@@ -1975,9 +1988,13 @@
} else {
jio_snprintf(message,
msglen,
- "%s cannot be cast to %s",
+ "class %s cannot be cast to class %s (%s%s%s)",
caster_name,
- target_name);
+ target_name,
+ caster_klass_description,
+ klass_separator,
+ target_klass_description
+ );
}
return message;
}
--- a/test/hotspot/jtreg/runtime/exceptionMsgs/IncompatibleClassChangeError/IncompatibleClassChangeErrorTest.java Mon Jun 25 20:36:06 2018 +0530
+++ b/test/hotspot/jtreg/runtime/exceptionMsgs/IncompatibleClassChangeError/IncompatibleClassChangeErrorTest.java Mon Jun 25 11:33:11 2018 -0400
@@ -212,7 +212,7 @@
}
private static String expectedErrorMessage3 =
- "Class test.ICC3_B can not implement test.ICC3_A, because it is not an interface";
+ "class test.ICC3_B can not implement test.ICC3_A, because it is not an interface (test.ICC3_A is in unnamed module of loader 'app')";
public static void test3_implementsClass() throws Exception {
try {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/modules/AccessCheck/ExpQualToM1PrivateMethodIAE.java Mon Jun 25 11:33:11 2018 -0400
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2018, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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
+ * @summary Test that if module m1x can read module m2x, AND package p2 in m2x is
+ * exported qualifiedly to m1x, then class p1.c1 in m1x can read p2.c2 in m2x.
+ * However, p1.c1 tries to access a private method within p2.c2, verify
+ * that the IAE message contains the correct loader and module names.
+ * @modules java.base/jdk.internal.misc
+ * @library /test/lib
+ * @compile p1/c1.jasm
+ * @compile p2/c2.jasm
+ * @compile myloaders/MySameClassLoader.java
+ * @run main/othervm -Xbootclasspath/a:. ExpQualToM1PrivateMethodIAE
+ */
+
+import static jdk.test.lib.Asserts.*;
+
+import java.lang.module.Configuration;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleFinder;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import myloaders.MySameClassLoader;
+
+public class ExpQualToM1PrivateMethodIAE {
+
+ // Create a layer over the boot layer.
+ // Define modules within this layer to test access between
+ // publically defined classes within packages of those modules.
+ public void createLayerOnBoot() throws Throwable {
+
+ // Define module: m1x
+ // Can read: java.base, m2x
+ // Packages: p1
+ // Packages exported: p1 is exported unqualifiedly
+ ModuleDescriptor descriptor_m1x =
+ ModuleDescriptor.newModule("m1x")
+ .requires("java.base")
+ .requires("m2x")
+ .exports("p1")
+ .build();
+
+ // Define module: m2x
+ // Can read: java.base
+ // Packages: p2
+ // Packages exported: p2 is exported qualifiedly to m1x
+ ModuleDescriptor descriptor_m2x =
+ ModuleDescriptor.newModule("m2x")
+ .requires("java.base")
+ .exports("p2", Set.of("m1x"))
+ .build();
+
+ // Set up a ModuleFinder containing all modules for this layer.
+ ModuleFinder finder = ModuleLibrary.of(descriptor_m1x, descriptor_m2x);
+
+ // Resolves "m1x"
+ Configuration cf = ModuleLayer.boot()
+ .configuration()
+ .resolve(finder, ModuleFinder.of(), Set.of("m1x"));
+
+ // map each module to the same class loader for this test
+ Map<String, ClassLoader> map = new HashMap<>();
+ map.put("m1x", MySameClassLoader.loader1);
+ map.put("m2x", MySameClassLoader.loader1);
+
+ // Create layer that contains m1x & m2x
+ ModuleLayer layer = ModuleLayer.boot().defineModules(cf, map::get);
+
+ assertTrue(layer.findLoader("m1x") == MySameClassLoader.loader1);
+ assertTrue(layer.findLoader("m2x") == MySameClassLoader.loader1);
+
+ // now use the same loader to load class p1.c1
+ Class p1_c1_class = MySameClassLoader.loader1.loadClass("p1.c1");
+ try {
+ p1_c1_class.newInstance();
+ throw new RuntimeException("Test Failed, an IAE should be thrown since p2/c2's method2 is private");
+ } catch (IllegalAccessError e) {
+ String message = e.getMessage();
+ System.out.println(e.toString());
+ // java.lang.IllegalAccessError:
+ // tried to access method p2.c2.method2()V from class p1.c1 (p2.c2 is in module m2x of loader
+ // myloaders.MySameClassLoader @<id>; p1.c1 is in module m1x of loader myloaders.MySameClassLoader @<id>)
+ if (!message.contains("class p1.c1 tried to access method p2.c2.method2()V (p1.c1 is in module m1x of loader myloaders.MySameClassLoader @") ||
+ !message.contains("; p2.c2 is in module m2x of loader myloaders.MySameClassLoader @")) {
+ throw new RuntimeException("Test Failed, an IAE was thrown with the wrong message: " + e.toString());
+ }
+ } catch (Throwable e) {
+ throw new RuntimeException("Test Failed, an IAE should be thrown since p2/c2's method2 is private");
+ }
+ }
+
+ public static void main(String args[]) throws Throwable {
+ ExpQualToM1PrivateMethodIAE test = new ExpQualToM1PrivateMethodIAE();
+ test.createLayerOnBoot();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/modules/AccessCheck/p1/c1.jasm Mon Jun 25 11:33:11 2018 -0400
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2018, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package p1;
+
+super public class c1 version 55:0 {
+
+ public Method "<init>":"()V"
+ stack 2 locals 2
+ {
+ aload_0;
+ invokespecial Method java/lang/Object."<init>":"()V";
+ new class p2/c2;
+ dup;
+ invokespecial Method p2/c2."<init>":"()V";
+ astore_1;
+ aload_1;
+ invokevirtual Method p2/c2.method2:"()V";
+ return;
+ }
+} // end Class c1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/modules/AccessCheck/p2/c2.jasm Mon Jun 25 11:33:11 2018 -0400
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2018, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package p2;
+
+super public class c2 version 55:0 {
+ public Method "<init>":"()V"
+ stack 1 locals 1
+ {
+ aload_0;
+ invokespecial Method java/lang/Object."<init>":"()V";
+ return;
+ }
+
+ private Method method2:"()V"
+ stack 0 locals 1
+ {
+ return;
+ }
+} // end Class c2
--- a/test/hotspot/jtreg/runtime/modules/CCE_module_msg.java Mon Jun 25 20:36:06 2018 +0530
+++ b/test/hotspot/jtreg/runtime/modules/CCE_module_msg.java Mon Jun 25 11:33:11 2018 -0400
@@ -48,6 +48,7 @@
public static void main(String[] args) throws Throwable {
// Should not display version
invalidObjectToDerived();
+ invalidOriginalInnerToDerived();
invalidTimeToDerived();
invalidHeadersToDerived();
// Should display version
@@ -66,8 +67,25 @@
}
throw new RuntimeException("ClassCastException wasn't thrown, test failed.");
} catch (ClassCastException cce) {
- System.out.println(cce.getMessage());
- if (!cce.getMessage().contains("java.base/java.lang.Object cannot be cast to Derived")) {
+ System.out.println(cce.toString());
+ if (!cce.getMessage().contains("class java.lang.Object cannot be cast to class Derived (java.lang.Object is in module java.base of loader 'bootstrap'; Derived is in unnamed module of loader 'app')")) {
+ throw new RuntimeException("Wrong message: " + cce.getMessage());
+ }
+ }
+ }
+
+ public static void invalidOriginalInnerToDerived() {
+ OriginalInner instance = new OriginalInner();
+ int left = 23;
+ int right = 42;
+ try {
+ for (int i = 0; i < 1; i += 1) {
+ left = ((Derived) (java.lang.Object)instance).method(left, right);
+ }
+ throw new RuntimeException("ClassCastException wasn't thrown, test failed.");
+ } catch (ClassCastException cce) {
+ System.out.println(cce.toString());
+ if (!cce.getMessage().contains("class OriginalInner cannot be cast to class Derived (OriginalInner and Derived are in unnamed module of loader 'app')")) {
throw new RuntimeException("Wrong message: " + cce.getMessage());
}
}
@@ -84,8 +102,8 @@
}
throw new RuntimeException("ClassCastException wasn't thrown, test failed.");
} catch (ClassCastException cce) {
- System.out.println(cce.getMessage());
- if (!cce.getMessage().contains("java.sql/java.sql.Time cannot be cast to Derived")) {
+ System.out.println(cce.toString());
+ if (!cce.getMessage().contains("class java.sql.Time cannot be cast to class Derived (java.sql.Time is in module java.sql of loader 'platform'; Derived is in unnamed module of loader 'app')")) {
throw new RuntimeException("Wrong message: " + cce.getMessage());
}
}
@@ -102,8 +120,8 @@
}
throw new RuntimeException("ClassCastException wasn't thrown, test failed.");
} catch (ClassCastException cce) {
- System.out.println(cce.getMessage());
- if (!cce.getMessage().contains("jdk.httpserver/com.sun.net.httpserver.Headers cannot be cast to Derived")) {
+ System.out.println(cce.toString());
+ if (!cce.getMessage().contains("class com.sun.net.httpserver.Headers cannot be cast to class Derived (com.sun.net.httpserver.Headers is in module jdk.httpserver of loader 'platform'; Derived is in unnamed module of loader 'app')")) {
throw new RuntimeException("Wrong message: " + cce.getMessage());
}
}
@@ -132,10 +150,9 @@
throw new RuntimeException("ClassCastException wasn't thrown, test failed.");
} catch (ClassCastException cce) {
String exception = cce.getMessage();
- System.out.println(exception);
- if (exception.contains("module_two/p2.c2") ||
- !(exception.contains("module_two@") &&
- exception.contains("/p2.c2 cannot be cast to java.base/java.lang.String"))) {
+ System.out.println(cce.toString());
+ if (!exception.contains("class p2.c2 cannot be cast to class java.lang.String (p2.c2 is in module module_two@") ||
+ !exception.contains(" of loader 'app'; java.lang.String is in module java.base of loader 'bootstrap')")) {
throw new RuntimeException("Wrong message: " + exception);
}
}
@@ -160,14 +177,21 @@
throw new RuntimeException("ClassCastException wasn't thrown, test failed.");
} catch (ClassCastException cce) {
String exception = cce.getMessage();
- System.out.println(exception);
- if (!exception.contains("MyClassLoader//p4.c4 cannot be cast to java.base/java.lang.String")) {
+ System.out.println(cce.toString());
+ if (!exception.contains("class p4.c4 cannot be cast to class java.lang.String (p4.c4 is in unnamed module of loader 'MyClassLoader' @") ||
+ !exception.contains("; java.lang.String is in module java.base of loader 'bootstrap')")) {
throw new RuntimeException("Wrong message: " + exception);
}
}
}
}
+class OriginalInner extends java.lang.Object {
+ public int method(int left, int right) {
+ return right;
+ }
+}
+
class Derived extends java.lang.Object {
public int method(int left, int right) {
return right;
--- a/test/hotspot/jtreg/vmTestbase/jit/t/t113/t113.gold Mon Jun 25 20:36:06 2018 +0530
+++ b/test/hotspot/jtreg/vmTestbase/jit/t/t113/t113.gold Mon Jun 25 11:33:11 2018 -0400
@@ -1,2 +1,2 @@
-java.lang.ClassCastException: jit.t.t113.kid1 cannot be cast to jit.t.t113.kid2
+java.lang.ClassCastException: class jit.t.t113.kid1 cannot be cast to class jit.t.t113.kid2 (jit.t.t113.kid1 and jit.t.t113.kid2 are in unnamed module of loader 'app')
at jit.t.t113.t113.main(t113.java:59)