8050079: crash while compiling java.lang.ref.Finalizer::runFinalizer
Summary: Ignore non-instance Klasses in the subclass hierarchy.
Reviewed-by: kvn, iignatyev, jrose
--- a/hotspot/src/share/vm/code/dependencies.cpp Tue Nov 18 19:44:45 2014 +0100
+++ b/hotspot/src/share/vm/code/dependencies.cpp Thu Nov 20 11:06:26 2014 +0100
@@ -912,6 +912,8 @@
bool is_witness(Klass* k) {
if (doing_subtype_search()) {
return Dependencies::is_concrete_klass(k);
+ } else if (!k->oop_is_instance()) {
+ return false; // no methods to find in an array type
} else {
Method* m = InstanceKlass::cast(k)->find_method(_name, _signature);
if (m == NULL || !Dependencies::is_concrete_method(m)) return false;
@@ -1118,7 +1120,7 @@
Klass* chain; // scratch variable
#define ADD_SUBCLASS_CHAIN(k) { \
assert(chaini < CHAINMAX, "oob"); \
- chain = InstanceKlass::cast(k)->subklass(); \
+ chain = k->subklass(); \
if (chain != NULL) chains[chaini++] = chain; }
// Look for non-abstract subclasses.
@@ -1129,35 +1131,37 @@
// (Their subclasses are additional indirect implementors.
// See InstanceKlass::add_implementor.)
// (Note: nof_implementors is always zero for non-interfaces.)
- int nof_impls = InstanceKlass::cast(context_type)->nof_implementors();
- if (nof_impls > 1) {
- // Avoid this case: *I.m > { A.m, C }; B.m > C
- // Here, I.m has 2 concrete implementations, but m appears unique
- // as A.m, because the search misses B.m when checking C.
- // The inherited method B.m was getting missed by the walker
- // when interface 'I' was the starting point.
- // %%% Until this is fixed more systematically, bail out.
- // (Old CHA had the same limitation.)
- return context_type;
- }
- if (nof_impls > 0) {
- Klass* impl = InstanceKlass::cast(context_type)->implementor();
- assert(impl != NULL, "just checking");
- // If impl is the same as the context_type, then more than one
- // implementor has seen. No exact info in this case.
- if (impl == context_type) {
- return context_type; // report an inexact witness to this sad affair
+ if (top_level_call) {
+ int nof_impls = InstanceKlass::cast(context_type)->nof_implementors();
+ if (nof_impls > 1) {
+ // Avoid this case: *I.m > { A.m, C }; B.m > C
+ // Here, I.m has 2 concrete implementations, but m appears unique
+ // as A.m, because the search misses B.m when checking C.
+ // The inherited method B.m was getting missed by the walker
+ // when interface 'I' was the starting point.
+ // %%% Until this is fixed more systematically, bail out.
+ // (Old CHA had the same limitation.)
+ return context_type;
}
- if (do_counts)
- { NOT_PRODUCT(deps_find_witness_steps++); }
- if (is_participant(impl)) {
- if (!participants_hide_witnesses) {
+ if (nof_impls > 0) {
+ Klass* impl = InstanceKlass::cast(context_type)->implementor();
+ assert(impl != NULL, "just checking");
+ // If impl is the same as the context_type, then more than one
+ // implementor has seen. No exact info in this case.
+ if (impl == context_type) {
+ return context_type; // report an inexact witness to this sad affair
+ }
+ if (do_counts)
+ { NOT_PRODUCT(deps_find_witness_steps++); }
+ if (is_participant(impl)) {
+ if (!participants_hide_witnesses) {
+ ADD_SUBCLASS_CHAIN(impl);
+ }
+ } else if (is_witness(impl) && !ignore_witness(impl)) {
+ return impl;
+ } else {
ADD_SUBCLASS_CHAIN(impl);
}
- } else if (is_witness(impl) && !ignore_witness(impl)) {
- return impl;
- } else {
- ADD_SUBCLASS_CHAIN(impl);
}
}
--- a/hotspot/test/TEST.groups Tue Nov 18 19:44:45 2014 +0100
+++ b/hotspot/test/TEST.groups Thu Nov 20 11:06:26 2014 +0100
@@ -344,6 +344,7 @@
compiler/codecache/ \
compiler/codegen/ \
compiler/cpuflags/ \
+ compiler/dependencies/ \
compiler/eliminateAutobox/ \
compiler/escapeAnalysis/ \
compiler/exceptions/ \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/dependencies/MonomorphicObjectCall/TestMonomorphicObjectCall.java Thu Nov 20 11:06:26 2014 +0100
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+
+import com.oracle.java.testlibrary.*;
+
+/*
+ * @test
+ * @bug 8050079
+ * @summary Compiles a monomorphic call to finalizeObject() on a modified java.lang.Object to test C1 CHA.
+ * @library /testlibrary
+ * @compile -XDignore.symbol.file java/lang/Object.java TestMonomorphicObjectCall.java
+ * @run main TestMonomorphicObjectCall
+ */
+public class TestMonomorphicObjectCall {
+ final static String testClasses = System.getProperty("test.classes") + File.separator;
+
+ private static void callFinalize(Object object) throws Throwable {
+ // Call modified version of java.lang.Object::finalize() that is
+ // not overridden by any subclass. C1 CHA should mark the call site
+ // as monomorphic and inline the method.
+ object.finalizeObject();
+ }
+
+ public static void main(String[] args) throws Throwable {
+ if (args.length == 0) {
+ // Execute new instance with modified java.lang.Object
+ executeTestJvm();
+ } else {
+ // Trigger compilation of 'callFinalize'
+ callFinalize(new Object());
+ }
+ }
+
+ public static void executeTestJvm() throws Throwable {
+ // Execute test with modified version of java.lang.Object
+ // in -Xbootclasspath.
+ String[] vmOpts = new String[] {
+ "-Xbootclasspath/p:" + testClasses,
+ "-Xcomp",
+ "-XX:-VerifyDependencies",
+ "-XX:CompileOnly=TestMonomorphicObjectCall::callFinalize",
+ "-XX:CompileOnly=Object::finalizeObject",
+ "-XX:TieredStopAtLevel=1",
+ TestMonomorphicObjectCall.class.getName(),
+ "true"};
+ OutputAnalyzer output = ProcessTools.executeTestJvm(vmOpts);
+ output.shouldHaveExitValue(0);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/dependencies/MonomorphicObjectCall/java/lang/Object.java Thu Nov 20 11:06:26 2014 +0100
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 1994, 2014, 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 java.lang;
+
+/**
+ * Slightly modified version of java.lang.Object that replaces
+ * finalize() by finalizeObject() to avoid overriding in subclasses.
+ */
+public class Object {
+
+ private static native void registerNatives();
+ static {
+ registerNatives();
+ }
+
+ public final native Class<?> getClass();
+
+ public native int hashCode();
+
+ public boolean equals(Object obj) {
+ return (this == obj);
+ }
+
+ protected native Object clone() throws CloneNotSupportedException;
+
+ public String toString() {
+ return getClass().getName() + "@" + Integer.toHexString(hashCode());
+ }
+
+ public final native void notify();
+
+ public final native void notifyAll();
+
+ public final native void wait(long timeout) throws InterruptedException;
+
+ public final void wait(long timeout, int nanos) throws InterruptedException {
+ if (timeout < 0) {
+ throw new IllegalArgumentException("timeout value is negative");
+ }
+
+ if (nanos < 0 || nanos > 999999) {
+ throw new IllegalArgumentException(
+ "nanosecond timeout value out of range");
+ }
+
+ if (nanos >= 500000 || (nanos != 0 && timeout == 0)) {
+ timeout++;
+ }
+
+ wait(timeout);
+ }
+
+ public final void wait() throws InterruptedException {
+ wait(0);
+ }
+
+ /**
+ * Replaces original finalize() method and is therefore not
+ * overridden by any subclasses of Object.
+ * @throws Throwable
+ */
+ // protected void finalize() throws Throwable { }
+ public void finalizeObject() throws Throwable { }
+}