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 23893cb3c263b..92c02c433c524 100644 --- a/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java +++ b/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java @@ -53,6 +53,8 @@ import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.classfile.constantpool.MethodRefEntry; import static java.lang.constant.ConstantDescs.*; +import static java.lang.invoke.MethodHandleNatives.Constants.NESTMATE_CLASS; +import static java.lang.invoke.MethodHandleNatives.Constants.STRONG_LOADER_LINK; import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE; import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG; import static java.lang.invoke.MethodType.methodType; @@ -348,7 +350,7 @@ else if (finalAccidentallySerializable) try { // this class is linked at the indy callsite; so define a hidden nestmate var classdata = useImplMethodHandle? implementation : null; - return caller.makeHiddenClassDefiner(lambdaClassName, classBytes, Set.of(NESTMATE, STRONG), lambdaProxyClassFileDumper) + return caller.makeHiddenClassDefiner(lambdaClassName, classBytes, lambdaProxyClassFileDumper, NESTMATE_CLASS | STRONG_LOADER_LINK) .defineClass(!disableEagerInitialization, classdata); } catch (Throwable t) { diff --git a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java index c69913ba6cd84..6031b55a107b2 100644 --- a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java +++ b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java @@ -47,7 +47,6 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; -import java.util.Set; import java.util.function.Consumer; import java.util.stream.Stream; import jdk.internal.constant.MethodTypeDescImpl; @@ -224,7 +223,7 @@ FieldRefEntry classData(ClassFileBuilder cfb, Object arg, ClassDesc desc) * Extract the MemberName of a newly-defined method. */ private MemberName loadMethod(byte[] classFile) { - Class invokerClass = LOOKUP.makeHiddenClassDefiner(className, classFile, Set.of(), dumper()) + Class invokerClass = LOOKUP.makeHiddenClassDefiner(className, classFile, dumper()) .defineClass(true, classDataValues()); return resolveInvokerMember(invokerClass, invokerName, invokerType); } diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java index 57446c9b2fdf0..f17bbd17c9467 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java @@ -64,6 +64,7 @@ import static java.lang.invoke.LambdaForm.*; import static java.lang.invoke.MethodHandleNatives.Constants.MN_CALLER_SENSITIVE; import static java.lang.invoke.MethodHandleNatives.Constants.MN_HIDDEN_MEMBER; +import static java.lang.invoke.MethodHandleNatives.Constants.NESTMATE_CLASS; import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE; @@ -1111,7 +1112,7 @@ private static Class makeInjectedInvoker(Class targetClass) { } name = name.replace('.', '/'); Class invokerClass = new Lookup(targetClass) - .makeHiddenClassDefiner(name, INJECTED_INVOKER_TEMPLATE, Set.of(NESTMATE), dumper()) + .makeHiddenClassDefiner(name, INJECTED_INVOKER_TEMPLATE, dumper(), NESTMATE_CLASS) .defineClass(true, targetClass); assert checkInjectedInvoker(targetClass, invokerClass); return invokerClass; diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java b/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java index 8f0f355a9802d..c6a5c2763f4a6 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java @@ -285,7 +285,7 @@ private static Class newProxyClass(Class intfc) { byte[] template = createTemplate(loader, binaryNameToDesc(className), referenceClassDesc(intfc), uniqueName, methods); // define the dynamic module to the class loader of the interface - var definer = new Lookup(intfc).makeHiddenClassDefiner(className, template, Set.of(), DUMPER); + var definer = new Lookup(intfc).makeHiddenClassDefiner(className, template, DUMPER); @SuppressWarnings("removal") var sm = System.getSecurityManager(); diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index 30c8ee03601f7..6a73266ae80a4 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -1906,9 +1906,12 @@ public enum ClassOption { this.flag = flag; } - static int optionsToFlag(Set options) { + static int optionsToFlag(ClassOption[] options) { int flags = 0; for (ClassOption cp : options) { + if ((flags & cp.flag) != 0) { + throw new IllegalArgumentException("Duplicate ClassOption " + cp); + } flags |= cp.flag; } return flags; @@ -2126,14 +2129,13 @@ public Lookup defineHiddenClass(byte[] bytes, boolean initialize, ClassOption... throws IllegalAccessException { Objects.requireNonNull(bytes); - Objects.requireNonNull(options); - + int flags = ClassOption.optionsToFlag(options); ensureDefineClassPermission(); if (!hasFullPrivilegeAccess()) { throw new IllegalAccessException(this + " does not have full privilege access"); } - return makeHiddenClassDefiner(bytes.clone(), Set.of(options), false).defineClassAsLookup(initialize); + return makeHiddenClassDefiner(bytes.clone(), false, flags).defineClassAsLookup(initialize); } /** @@ -2213,14 +2215,15 @@ public Lookup defineHiddenClassWithClassData(byte[] bytes, Object classData, boo { Objects.requireNonNull(bytes); Objects.requireNonNull(classData); - Objects.requireNonNull(options); + + int flags = ClassOption.optionsToFlag(options); ensureDefineClassPermission(); if (!hasFullPrivilegeAccess()) { throw new IllegalAccessException(this + " does not have full privilege access"); } - return makeHiddenClassDefiner(bytes.clone(), Set.of(options), false) + return makeHiddenClassDefiner(bytes.clone(), false, flags) .defineClassAsLookup(initialize, classData); } @@ -2366,7 +2369,7 @@ ClassDefiner makeClassDefiner(String name, byte[] bytes, ClassFileDumper dumper) */ ClassDefiner makeHiddenClassDefiner(byte[] bytes, ClassFileDumper dumper) { ClassFile cf = ClassFile.newInstance(bytes, lookupClass().getPackageName()); - return makeHiddenClassDefiner(cf, Set.of(), false, dumper); + return makeHiddenClassDefiner(cf, false, dumper, 0); } /** @@ -2378,7 +2381,7 @@ ClassDefiner makeHiddenClassDefiner(byte[] bytes, ClassFileDumper dumper) { * before calling this factory method. * * @param bytes class bytes - * @param options class options + * @param flags class option flag mask * @param accessVmAnnotations true to give the hidden class access to VM annotations * @return ClassDefiner that defines a hidden class of the given bytes and options * @@ -2386,10 +2389,25 @@ ClassDefiner makeHiddenClassDefiner(byte[] bytes, ClassFileDumper dumper) { * {@code bytes} denotes a class in a different package than the lookup class */ private ClassDefiner makeHiddenClassDefiner(byte[] bytes, - Set options, - boolean accessVmAnnotations) { + boolean accessVmAnnotations, + int flags) { ClassFile cf = ClassFile.newInstance(bytes, lookupClass().getPackageName()); - return makeHiddenClassDefiner(cf, options, accessVmAnnotations, defaultDumper()); + return makeHiddenClassDefiner(cf, accessVmAnnotations, defaultDumper(), flags); + } + + /** + * Returns a ClassDefiner that creates a {@code Class} object of a hidden class + * from the given bytes and the given options. No package name check on the given bytes. + * + * @param name internal name that specifies the prefix of the hidden class + * @param bytes class bytes + * @param dumper dumper to write the given bytes to the dumper's output directory + * @return ClassDefiner that defines a hidden class of the given bytes and options. + */ + ClassDefiner makeHiddenClassDefiner(String name, byte[] bytes, ClassFileDumper dumper) { + Objects.requireNonNull(dumper); + // skip name and access flags validation + return makeHiddenClassDefiner(ClassFile.newInstanceNoCheck(name, bytes), false, dumper, 0); } /** @@ -2398,14 +2416,14 @@ private ClassDefiner makeHiddenClassDefiner(byte[] bytes, * * @param name internal name that specifies the prefix of the hidden class * @param bytes class bytes - * @param options class options + * @param flags class options flag mask * @param dumper dumper to write the given bytes to the dumper's output directory * @return ClassDefiner that defines a hidden class of the given bytes and options. */ - ClassDefiner makeHiddenClassDefiner(String name, byte[] bytes, Set options, ClassFileDumper dumper) { + ClassDefiner makeHiddenClassDefiner(String name, byte[] bytes, ClassFileDumper dumper, int flags) { Objects.requireNonNull(dumper); // skip name and access flags validation - return makeHiddenClassDefiner(ClassFile.newInstanceNoCheck(name, bytes), options, false, dumper); + return makeHiddenClassDefiner(ClassFile.newInstanceNoCheck(name, bytes), false, dumper, flags); } /** @@ -2413,15 +2431,15 @@ ClassDefiner makeHiddenClassDefiner(String name, byte[] bytes, Set * from the given class file and options. * * @param cf ClassFile - * @param options class options + * @param flags class option flag mask * @param accessVmAnnotations true to give the hidden class access to VM annotations * @param dumper dumper to write the given bytes to the dumper's output directory */ private ClassDefiner makeHiddenClassDefiner(ClassFile cf, - Set options, boolean accessVmAnnotations, - ClassFileDumper dumper) { - int flags = HIDDEN_CLASS | ClassOption.optionsToFlag(options); + ClassFileDumper dumper, + int flags) { + flags |= HIDDEN_CLASS; if (accessVmAnnotations | VM.isSystemDomainLoader(lookupClass.getClassLoader())) { // jdk.internal.vm.annotations are permitted for classes // defined to boot loader and platform loader diff --git a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java index ab429899d30f8..4fbbec1769364 100644 --- a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java +++ b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java @@ -51,7 +51,6 @@ import java.lang.ref.SoftReference; import java.util.Map; import java.util.Objects; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; import java.util.function.Supplier; @@ -1353,7 +1352,7 @@ public void accept(MethodBuilder mb) { } }}); try { - var hiddenClass = lookup.makeHiddenClassDefiner(CLASS_NAME, classBytes, Set.of(), DUMPER) + var hiddenClass = lookup.makeHiddenClassDefiner(CLASS_NAME, classBytes, DUMPER) .defineClass(true, null); if (staticConcat) {