8340131: Refactor internal makeHiddenClassDefiner to take option mask instead of Set<ClassOption>

Reviewed-by: liach, jvernee
This commit is contained in:
Claes Redestad 2024-09-16 14:08:08 +00:00
parent 05b9d47905
commit e1ebeef040
6 changed files with 44 additions and 25 deletions

View file

@ -53,6 +53,8 @@ import java.lang.classfile.constantpool.ClassEntry;
import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.classfile.constantpool.ConstantPoolBuilder;
import java.lang.classfile.constantpool.MethodRefEntry; import java.lang.classfile.constantpool.MethodRefEntry;
import static java.lang.constant.ConstantDescs.*; 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.NESTMATE;
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG; import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG;
import static java.lang.invoke.MethodType.methodType; import static java.lang.invoke.MethodType.methodType;
@ -348,7 +350,7 @@ import sun.invoke.util.Wrapper;
try { try {
// this class is linked at the indy callsite; so define a hidden nestmate // this class is linked at the indy callsite; so define a hidden nestmate
var classdata = useImplMethodHandle? implementation : null; 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); .defineClass(!disableEagerInitialization, classdata);
} catch (Throwable t) { } catch (Throwable t) {

View file

@ -47,7 +47,6 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Stream; import java.util.stream.Stream;
import jdk.internal.constant.MethodTypeDescImpl; import jdk.internal.constant.MethodTypeDescImpl;
@ -224,7 +223,7 @@ class InvokerBytecodeGenerator {
* Extract the MemberName of a newly-defined method. * Extract the MemberName of a newly-defined method.
*/ */
private MemberName loadMethod(byte[] classFile) { private MemberName loadMethod(byte[] classFile) {
Class<?> invokerClass = LOOKUP.makeHiddenClassDefiner(className, classFile, Set.of(), dumper()) Class<?> invokerClass = LOOKUP.makeHiddenClassDefiner(className, classFile, dumper())
.defineClass(true, classDataValues()); .defineClass(true, classDataValues());
return resolveInvokerMember(invokerClass, invokerName, invokerType); return resolveInvokerMember(invokerClass, invokerName, invokerType);
} }

View file

@ -64,6 +64,7 @@ import static java.lang.constant.ConstantDescs.*;
import static java.lang.invoke.LambdaForm.*; import static java.lang.invoke.LambdaForm.*;
import static java.lang.invoke.MethodHandleNatives.Constants.MN_CALLER_SENSITIVE; 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.MN_HIDDEN_MEMBER;
import static java.lang.invoke.MethodHandleNatives.Constants.NESTMATE_CLASS;
import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE; import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
@ -1111,7 +1112,7 @@ abstract class MethodHandleImpl {
} }
name = name.replace('.', '/'); name = name.replace('.', '/');
Class<?> invokerClass = new Lookup(targetClass) 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); .defineClass(true, targetClass);
assert checkInjectedInvoker(targetClass, invokerClass); assert checkInjectedInvoker(targetClass, invokerClass);
return invokerClass; return invokerClass;

View file

@ -285,7 +285,7 @@ public class MethodHandleProxies {
byte[] template = createTemplate(loader, binaryNameToDesc(className), byte[] template = createTemplate(loader, binaryNameToDesc(className),
referenceClassDesc(intfc), uniqueName, methods); referenceClassDesc(intfc), uniqueName, methods);
// define the dynamic module to the class loader of the interface // 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") @SuppressWarnings("removal")
var sm = System.getSecurityManager(); var sm = System.getSecurityManager();

View file

@ -1906,9 +1906,12 @@ public class MethodHandles {
this.flag = flag; this.flag = flag;
} }
static int optionsToFlag(Set<ClassOption> options) { static int optionsToFlag(ClassOption[] options) {
int flags = 0; int flags = 0;
for (ClassOption cp : options) { for (ClassOption cp : options) {
if ((flags & cp.flag) != 0) {
throw new IllegalArgumentException("Duplicate ClassOption " + cp);
}
flags |= cp.flag; flags |= cp.flag;
} }
return flags; return flags;
@ -2126,14 +2129,13 @@ public class MethodHandles {
throws IllegalAccessException throws IllegalAccessException
{ {
Objects.requireNonNull(bytes); Objects.requireNonNull(bytes);
Objects.requireNonNull(options); int flags = ClassOption.optionsToFlag(options);
ensureDefineClassPermission(); ensureDefineClassPermission();
if (!hasFullPrivilegeAccess()) { if (!hasFullPrivilegeAccess()) {
throw new IllegalAccessException(this + " does not have full privilege access"); 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 class MethodHandles {
{ {
Objects.requireNonNull(bytes); Objects.requireNonNull(bytes);
Objects.requireNonNull(classData); Objects.requireNonNull(classData);
Objects.requireNonNull(options);
int flags = ClassOption.optionsToFlag(options);
ensureDefineClassPermission(); ensureDefineClassPermission();
if (!hasFullPrivilegeAccess()) { if (!hasFullPrivilegeAccess()) {
throw new IllegalAccessException(this + " does not have full privilege access"); 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); .defineClassAsLookup(initialize, classData);
} }
@ -2366,7 +2369,7 @@ public class MethodHandles {
*/ */
ClassDefiner makeHiddenClassDefiner(byte[] bytes, ClassFileDumper dumper) { ClassDefiner makeHiddenClassDefiner(byte[] bytes, ClassFileDumper dumper) {
ClassFile cf = ClassFile.newInstance(bytes, lookupClass().getPackageName()); ClassFile cf = ClassFile.newInstance(bytes, lookupClass().getPackageName());
return makeHiddenClassDefiner(cf, Set.of(), false, dumper); return makeHiddenClassDefiner(cf, false, dumper, 0);
} }
/** /**
@ -2378,7 +2381,7 @@ public class MethodHandles {
* before calling this factory method. * before calling this factory method.
* *
* @param bytes class bytes * @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 * @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 * @return ClassDefiner that defines a hidden class of the given bytes and options
* *
@ -2386,10 +2389,10 @@ public class MethodHandles {
* {@code bytes} denotes a class in a different package than the lookup class * {@code bytes} denotes a class in a different package than the lookup class
*/ */
private ClassDefiner makeHiddenClassDefiner(byte[] bytes, private ClassDefiner makeHiddenClassDefiner(byte[] bytes,
Set<ClassOption> options, boolean accessVmAnnotations,
boolean accessVmAnnotations) { int flags) {
ClassFile cf = ClassFile.newInstance(bytes, lookupClass().getPackageName()); ClassFile cf = ClassFile.newInstance(bytes, lookupClass().getPackageName());
return makeHiddenClassDefiner(cf, options, accessVmAnnotations, defaultDumper()); return makeHiddenClassDefiner(cf, accessVmAnnotations, defaultDumper(), flags);
} }
/** /**
@ -2398,14 +2401,29 @@ public class MethodHandles {
* *
* @param name internal name that specifies the prefix of the hidden class * @param name internal name that specifies the prefix of the hidden class
* @param bytes class bytes * @param bytes class bytes
* @param options class options
* @param dumper dumper to write the given bytes to the dumper's output directory * @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. * @return ClassDefiner that defines a hidden class of the given bytes and options.
*/ */
ClassDefiner makeHiddenClassDefiner(String name, byte[] bytes, Set<ClassOption> options, ClassFileDumper dumper) { ClassDefiner makeHiddenClassDefiner(String name, byte[] bytes, ClassFileDumper dumper) {
Objects.requireNonNull(dumper); Objects.requireNonNull(dumper);
// skip name and access flags validation // skip name and access flags validation
return makeHiddenClassDefiner(ClassFile.newInstanceNoCheck(name, bytes), options, false, dumper); return makeHiddenClassDefiner(ClassFile.newInstanceNoCheck(name, bytes), false, dumper, 0);
}
/**
* 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 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, ClassFileDumper dumper, int flags) {
Objects.requireNonNull(dumper);
// skip name and access flags validation
return makeHiddenClassDefiner(ClassFile.newInstanceNoCheck(name, bytes), false, dumper, flags);
} }
/** /**
@ -2413,15 +2431,15 @@ public class MethodHandles {
* from the given class file and options. * from the given class file and options.
* *
* @param cf ClassFile * @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 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 * @param dumper dumper to write the given bytes to the dumper's output directory
*/ */
private ClassDefiner makeHiddenClassDefiner(ClassFile cf, private ClassDefiner makeHiddenClassDefiner(ClassFile cf,
Set<ClassOption> options,
boolean accessVmAnnotations, boolean accessVmAnnotations,
ClassFileDumper dumper) { ClassFileDumper dumper,
int flags = HIDDEN_CLASS | ClassOption.optionsToFlag(options); int flags) {
flags |= HIDDEN_CLASS;
if (accessVmAnnotations | VM.isSystemDomainLoader(lookupClass.getClassLoader())) { if (accessVmAnnotations | VM.isSystemDomainLoader(lookupClass.getClassLoader())) {
// jdk.internal.vm.annotations are permitted for classes // jdk.internal.vm.annotations are permitted for classes
// defined to boot loader and platform loader // defined to boot loader and platform loader

View file

@ -51,7 +51,6 @@ import java.lang.invoke.MethodHandles.Lookup;
import java.lang.ref.SoftReference; import java.lang.ref.SoftReference;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
@ -1353,7 +1352,7 @@ public final class StringConcatFactory {
} }
}}); }});
try { try {
var hiddenClass = lookup.makeHiddenClassDefiner(CLASS_NAME, classBytes, Set.of(), DUMPER) var hiddenClass = lookup.makeHiddenClassDefiner(CLASS_NAME, classBytes, DUMPER)
.defineClass(true, null); .defineClass(true, null);
if (staticConcat) { if (staticConcat) {