diff --git a/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java b/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java index 83b2b21562e..b4afbc098c9 100644 --- a/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java +++ b/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java @@ -175,13 +175,15 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; lambdaClassName = lambdaClassName(targetClass); // If the target class invokes a protected method inherited from a // superclass in a different package, or does 'invokespecial', the - // lambda class has no access to the resolved method. Instead, we need - // to pass the live implementation method handle to the proxy class - // to invoke directly. (javac prefers to avoid this situation by - // generating bridges in the target class) + // lambda class has no access to the resolved method, or does + // 'invokestatic' on a hidden class which cannot be resolved by name. + // Instead, we need to pass the live implementation method handle to + // the proxy class to invoke directly. (javac prefers to avoid this + // situation by generating bridges in the target class) useImplMethodHandle = (Modifier.isProtected(implInfo.getModifiers()) && !VerifyAccess.isSamePackage(targetClass, implInfo.getDeclaringClass())) || - implKind == H_INVOKESPECIAL; + implKind == H_INVOKESPECIAL || + implKind == H_INVOKESTATIC && implClass.isHidden(); cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); int parameterCount = factoryType.parameterCount(); if (parameterCount > 0) { diff --git a/test/jdk/java/lang/invoke/defineHiddenClass/BasicTest.java b/test/jdk/java/lang/invoke/defineHiddenClass/BasicTest.java index 2ca27be4248..08138a86ed0 100644 --- a/test/jdk/java/lang/invoke/defineHiddenClass/BasicTest.java +++ b/test/jdk/java/lang/invoke/defineHiddenClass/BasicTest.java @@ -23,6 +23,7 @@ /* * @test + * @bug 8330467 * @modules jdk.compiler * @library /test/lib * @enablePreview @@ -181,6 +182,20 @@ public class BasicTest { } } + // Define a hidden class that uses lambda and contains its implementation + // This verifies LambdaMetaFactory supports the caller which is a hidden class + @Test + public void testHiddenLambda() throws Throwable { + HiddenTest t = (HiddenTest)defineHiddenClass("HiddenLambda").newInstance(); + try { + t.test(); + } catch (Error e) { + if (!e.getMessage().equals("thrown by " + t.getClass().getName())) { + throw e; + } + } + } + // Verify the nest host and nest members of a hidden class and hidden nestmate class @Test public void testHiddenNestHost() throws Throwable { diff --git a/test/jdk/java/lang/invoke/defineHiddenClass/src/HiddenLambda.java b/test/jdk/java/lang/invoke/defineHiddenClass/src/HiddenLambda.java new file mode 100644 index 00000000000..f7a6e7a58da --- /dev/null +++ b/test/jdk/java/lang/invoke/defineHiddenClass/src/HiddenLambda.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +import java.util.function.Function; + +public class HiddenLambda implements HiddenTest { + public void test() { + Function f = o -> o.toString(); + String s = f.apply(this); + throw new Error("thrown by " + s); + } + + public String toString() { + return getClass().getName(); + } +}