mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 06:45:07 +02:00
8332547: Unloaded signature classes in DirectMethodHandles
Reviewed-by: jvernee, liach
This commit is contained in:
parent
c7d2a5c1c4
commit
29e10e4582
4 changed files with 83 additions and 15 deletions
|
@ -632,7 +632,7 @@ class InvokerBytecodeGenerator {
|
||||||
else if (c == Object[].class) return OBJARY;
|
else if (c == Object[].class) return OBJARY;
|
||||||
else if (c == Class.class) return CLS;
|
else if (c == Class.class) return CLS;
|
||||||
else if (c == MethodHandle.class) return MH;
|
else if (c == MethodHandle.class) return MH;
|
||||||
assert(VerifyAccess.isTypeVisible(c, Object.class)) : c.getName();
|
assert(VerifyAccess.ensureTypeVisible(c, Object.class)) : c.getName();
|
||||||
|
|
||||||
if (c == lastClass) {
|
if (c == lastClass) {
|
||||||
return lastInternalName;
|
return lastInternalName;
|
||||||
|
|
|
@ -800,7 +800,7 @@ final class MemberName implements Member, Cloneable {
|
||||||
assert(isResolved() == isResolved);
|
assert(isResolved() == isResolved);
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkForTypeAlias(Class<?> refc) {
|
void ensureTypeVisible(Class<?> refc) {
|
||||||
if (isInvocable()) {
|
if (isInvocable()) {
|
||||||
MethodType type;
|
MethodType type;
|
||||||
if (this.type instanceof MethodType mt)
|
if (this.type instanceof MethodType mt)
|
||||||
|
@ -808,7 +808,7 @@ final class MemberName implements Member, Cloneable {
|
||||||
else
|
else
|
||||||
this.type = type = getMethodType();
|
this.type = type = getMethodType();
|
||||||
if (type.erase() == type) return;
|
if (type.erase() == type) return;
|
||||||
if (VerifyAccess.isTypeVisible(type, refc)) return;
|
if (VerifyAccess.ensureTypeVisible(type, refc)) return;
|
||||||
throw new LinkageError("bad method type alias: "+type+" not visible from "+refc);
|
throw new LinkageError("bad method type alias: "+type+" not visible from "+refc);
|
||||||
} else {
|
} else {
|
||||||
Class<?> type;
|
Class<?> type;
|
||||||
|
@ -816,7 +816,7 @@ final class MemberName implements Member, Cloneable {
|
||||||
type = cl;
|
type = cl;
|
||||||
else
|
else
|
||||||
this.type = type = getFieldType();
|
this.type = type = getFieldType();
|
||||||
if (VerifyAccess.isTypeVisible(type, refc)) return;
|
if (VerifyAccess.ensureTypeVisible(type, refc)) return;
|
||||||
throw new LinkageError("bad field type alias: "+type+" not visible from "+refc);
|
throw new LinkageError("bad field type alias: "+type+" not visible from "+refc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -958,7 +958,7 @@ final class MemberName implements Member, Cloneable {
|
||||||
if (m == null && speculativeResolve) {
|
if (m == null && speculativeResolve) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
m.checkForTypeAlias(m.getDeclaringClass());
|
m.ensureTypeVisible(m.getDeclaringClass());
|
||||||
m.resolution = null;
|
m.resolution = null;
|
||||||
} catch (ClassNotFoundException | LinkageError ex) {
|
} catch (ClassNotFoundException | LinkageError ex) {
|
||||||
// JVM reports that the "bytecode behavior" would get an error
|
// JVM reports that the "bytecode behavior" would get an error
|
||||||
|
|
|
@ -268,7 +268,7 @@ public class VerifyAccess {
|
||||||
* @param type the supposed type of a member or symbolic reference of refc
|
* @param type the supposed type of a member or symbolic reference of refc
|
||||||
* @param refc the class attempting to make the reference
|
* @param refc the class attempting to make the reference
|
||||||
*/
|
*/
|
||||||
public static boolean isTypeVisible(Class<?> type, Class<?> refc) {
|
public static boolean ensureTypeVisible(Class<?> type, Class<?> refc) {
|
||||||
if (type == refc) {
|
if (type == refc) {
|
||||||
return true; // easy check
|
return true; // easy check
|
||||||
}
|
}
|
||||||
|
@ -284,12 +284,14 @@ public class VerifyAccess {
|
||||||
if (refcLoader == null && typeLoader != null) {
|
if (refcLoader == null && typeLoader != null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (typeLoader == null && type.getName().startsWith("java.")) {
|
|
||||||
// Note: The API for actually loading classes, ClassLoader.defineClass,
|
// The API for actually loading classes, ClassLoader.defineClass,
|
||||||
// guarantees that classes with names beginning "java." cannot be aliased,
|
// guarantees that classes with names beginning "java." cannot be aliased,
|
||||||
// because class loaders cannot load them directly.
|
// because class loaders cannot load them directly. However, it is beneficial
|
||||||
return true;
|
// for JIT-compilers to ensure all signature classes are loaded.
|
||||||
}
|
// JVM doesn't install any loader contraints when performing MemberName resolution,
|
||||||
|
// so eagerly resolving signature classes is a way to match what JVM achieves
|
||||||
|
// with loader constraints during method resolution for invoke bytecodes.
|
||||||
|
|
||||||
// Do it the hard way: Look up the type name from the refc loader.
|
// Do it the hard way: Look up the type name from the refc loader.
|
||||||
//
|
//
|
||||||
|
@ -338,12 +340,12 @@ public class VerifyAccess {
|
||||||
* @param type the supposed type of a member or symbolic reference of refc
|
* @param type the supposed type of a member or symbolic reference of refc
|
||||||
* @param refc the class attempting to make the reference
|
* @param refc the class attempting to make the reference
|
||||||
*/
|
*/
|
||||||
public static boolean isTypeVisible(java.lang.invoke.MethodType type, Class<?> refc) {
|
public static boolean ensureTypeVisible(java.lang.invoke.MethodType type, Class<?> refc) {
|
||||||
if (!isTypeVisible(type.returnType(), refc)) {
|
if (!ensureTypeVisible(type.returnType(), refc)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (int n = 0, max = type.parameterCount(); n < max; n++) {
|
for (int n = 0, max = type.parameterCount(); n < max; n++) {
|
||||||
if (!isTypeVisible(type.parameterType(n), refc)) {
|
if (!ensureTypeVisible(type.parameterType(n), refc)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024, 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
|
||||||
|
* @library /test/lib
|
||||||
|
* @run driver compiler.runtime.unloaded.TestUnloadedSignatureClass
|
||||||
|
*/
|
||||||
|
|
||||||
|
package compiler.runtime.unloaded;
|
||||||
|
|
||||||
|
import jdk.test.lib.process.OutputAnalyzer;
|
||||||
|
import jdk.test.lib.process.ProcessTools;
|
||||||
|
|
||||||
|
public class TestUnloadedSignatureClass {
|
||||||
|
static class Test {
|
||||||
|
static int test(Integer i) {
|
||||||
|
// Bound to a wrapper around a method with (Ljava/lang/Object;ILjava/util/function/BiPredicate;Ljava/util/List;)I signature.
|
||||||
|
// Neither BiPredicate nor List are guaranteed to be resolved by the context class loader.
|
||||||
|
return switch (i) {
|
||||||
|
case null -> -1;
|
||||||
|
case 0 -> 0;
|
||||||
|
default -> 1;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
for (int i = 0; i < 20_000; i++) {
|
||||||
|
test(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(
|
||||||
|
"-Xbatch", "-XX:-TieredCompilation",
|
||||||
|
"-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,*::test",
|
||||||
|
"-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintCompilation", "-XX:+PrintInlining",
|
||||||
|
Test.class.getName()
|
||||||
|
);
|
||||||
|
|
||||||
|
OutputAnalyzer out = new OutputAnalyzer(pb.start());
|
||||||
|
out.shouldHaveExitValue(0);
|
||||||
|
out.shouldNotContain("unloaded signature classes");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue