Skip to content

Commit

Permalink
8271820: Implementation of JEP 416: Reimplement Core Reflection with …
Browse files Browse the repository at this point in the history
…Method Handle

8013527: calling MethodHandles.lookup on itself leads to errors

Co-authored-by: Peter Levart <plevart@openjdk.org>
Co-authored-by: Claes Redestad <redestad@openjdk.org>
Co-authored-by: Mandy Chung <mchung@openjdk.org>
Reviewed-by: mcimadamore, plevart, egahlin, redestad, cjplummer, alanb
  • Loading branch information
3 people committed Oct 28, 2021
1 parent 5a768f7 commit c6339cb
Show file tree
Hide file tree
Showing 78 changed files with 6,119 additions and 545 deletions.
12 changes: 12 additions & 0 deletions make/jdk/src/classes/build/tools/classlist/HelloClasslist.java
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ public static void main(String ... args) throws Throwable {
DateFormat.getDateInstance(DateFormat.DEFAULT, Locale.ROOT)
.format(new Date()));

// A selection of trivial and common reflection operations
var instance = HelloClasslist.class.getConstructor().newInstance();
HelloClasslist.class.getMethod("staticMethod_V").invoke(null);
var obj = HelloClasslist.class.getMethod("staticMethod_L_L", Object.class).invoke(null, instance);
HelloClasslist.class.getField("field").get(instance);

// A selection of trivial and relatively common MH operations
invoke(MethodHandles.identity(double.class), 1.0);
invoke(MethodHandles.identity(int.class), 1);
Expand All @@ -126,8 +132,14 @@ public static void main(String ... args) throws Throwable {
LOGGER.log(Level.FINE, "New Date: " + newDate + " - old: " + oldDate);
}

public HelloClasslist() {}

public String field = "someValue";

public static void staticMethod_V() {}

public static Object staticMethod_L_L(Object o) { return o; }

private static MethodHandle handle(String name, MethodType type) throws Throwable {
return MethodHandles.lookup().findStatic(HelloClasslist.class, name, type);
}
Expand Down
1 change: 1 addition & 0 deletions src/hotspot/share/ci/ciField.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ static bool trust_final_non_static_fields(ciInstanceKlass* holder) {
return false;
// Even if general trusting is disabled, trust system-built closures in these packages.
if (holder->is_in_package("java/lang/invoke") || holder->is_in_package("sun/invoke") ||
holder->is_in_package("java/lang/reflect") || holder->is_in_package("jdk/internal/reflect") ||
holder->is_in_package("jdk/internal/foreign") || holder->is_in_package("jdk/incubator/foreign") ||
holder->is_in_package("jdk/internal/vm/vector") || holder->is_in_package("jdk/incubator/vector") ||
holder->is_in_package("java/lang"))
Expand Down
38 changes: 35 additions & 3 deletions src/java.base/share/classes/java/lang/Class.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
import jdk.internal.misc.Unsafe;
import jdk.internal.module.Resources;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.CallerSensitiveAdapter;
import jdk.internal.reflect.ConstantPool;
import jdk.internal.reflect.Reflection;
import jdk.internal.reflect.ReflectionFactory;
Expand Down Expand Up @@ -372,9 +373,15 @@ static String typeVarBounds(TypeVariable<?> typeVar) {
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
return forName(className, caller);
}

// Caller-sensitive adapter method for reflective invocation
@CallerSensitiveAdapter
private static Class<?> forName(String className, Class<?> caller)
throws ClassNotFoundException {
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

/**
* Returns the {@code Class} object associated with the class or
Expand Down Expand Up @@ -456,11 +463,25 @@ public static Class<?> forName(String name, boolean initialize,
// Reflective call to get caller class is only needed if a security manager
// is present. Avoid the overhead of making this call otherwise.
caller = Reflection.getCallerClass();
}
return forName(name, initialize, loader, caller);
}

// Caller-sensitive adapter method for reflective invocation
@CallerSensitiveAdapter
private static Class<?> forName(String name, boolean initialize, ClassLoader loader, Class<?> caller)
throws ClassNotFoundException
{
@SuppressWarnings("removal")
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
// Reflective call to get caller class is only needed if a security manager
// is present. Avoid the overhead of making this call otherwise.
if (loader == null) {
ClassLoader ccl = ClassLoader.getClassLoader(caller);
if (ccl != null) {
sm.checkPermission(
SecurityConstants.GET_CLASSLOADER_PERMISSION);
SecurityConstants.GET_CLASSLOADER_PERMISSION);
}
}
}
Expand Down Expand Up @@ -523,13 +544,24 @@ private static native Class<?> forName0(String name, boolean initialize,
@SuppressWarnings("removal")
@CallerSensitive
public static Class<?> forName(Module module, String name) {
Class<?> caller = null;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
caller = Reflection.getCallerClass();
}
return forName(module, name, caller);
}

// Caller-sensitive adapter method for reflective invocation
@SuppressWarnings("removal")
@CallerSensitiveAdapter
private static Class<?> forName(Module module, String name, Class<?> caller) {
Objects.requireNonNull(module);
Objects.requireNonNull(name);

ClassLoader cl;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
Class<?> caller = Reflection.getCallerClass();
if (caller != null && caller.getModule() != module) {
// if caller is null, Class.forName is the last java frame on the stack.
// java.base has all permissions
Expand Down
11 changes: 8 additions & 3 deletions src/java.base/share/classes/java/lang/ClassLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
import jdk.internal.misc.Unsafe;
import jdk.internal.misc.VM;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.CallerSensitiveAdapter;
import jdk.internal.reflect.Reflection;
import jdk.internal.util.StaticProperty;
import sun.reflect.misc.ReflectUtil;
Expand Down Expand Up @@ -1615,9 +1616,13 @@ protected Enumeration<URL> findResources(String name) throws IOException {
*/
@CallerSensitive
protected static boolean registerAsParallelCapable() {
Class<? extends ClassLoader> callerClass =
Reflection.getCallerClass().asSubclass(ClassLoader.class);
return ParallelLoaders.register(callerClass);
return registerAsParallelCapable(Reflection.getCallerClass());
}

// Caller-sensitive adapter method for reflective invocation
@CallerSensitiveAdapter
private static boolean registerAsParallelCapable(Class<?> caller) {
return ParallelLoaders.register(caller.asSubclass(ClassLoader.class));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
package java.lang.invoke;

import jdk.internal.misc.CDS;
import jdk.internal.misc.VM;
import jdk.internal.org.objectweb.asm.*;
import sun.invoke.util.BytecodeDescriptor;
import sun.invoke.util.VerifyAccess;
Expand All @@ -37,7 +36,6 @@
import java.io.Serializable;
import java.lang.constant.ConstantDescs;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedAction;
Expand All @@ -46,8 +44,10 @@
import java.util.PropertyPermission;
import java.util.Set;

import static java.lang.invoke.MethodHandleStatics.CLASSFILE_VERSION;
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;
import static jdk.internal.org.objectweb.asm.Opcodes.*;

/**
Expand All @@ -57,7 +57,6 @@
* @see LambdaMetafactory
*/
/* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
private static final int CLASSFILE_VERSION = VM.classFileVersion();
private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
private static final String JAVA_LANG_OBJECT = "java/lang/Object";
private static final String NAME_CTOR = "<init>";
Expand Down Expand Up @@ -106,7 +105,7 @@
disableEagerInitialization = GetBooleanAction.privilegedGetProperty(disableEagerInitializationKey);

// condy to load implMethod from class data
MethodType classDataMType = MethodType.methodType(Object.class, MethodHandles.Lookup.class, String.class, Class.class);
MethodType classDataMType = methodType(Object.class, MethodHandles.Lookup.class, String.class, Class.class);
Handle classDataBsm = new Handle(H_INVOKESTATIC, Type.getInternalName(MethodHandles.class), "classData",
classDataMType.descriptorString(), false);
implMethodCondy = new ConstantDynamic(ConstantDescs.DEFAULT_NAME, MethodHandle.class.descriptorString(), classDataBsm);
Expand Down Expand Up @@ -227,50 +226,28 @@ private static String lambdaClassName(Class<?> targetClass) {
@Override
CallSite buildCallSite() throws LambdaConversionException {
final Class<?> innerClass = spinInnerClass();
if (factoryType.parameterCount() == 0) {
// In the case of a non-capturing lambda, we optimize linkage by pre-computing a single instance,
// unless we've suppressed eager initialization
if (disableEagerInitialization) {
try {
return new ConstantCallSite(caller.findStaticGetter(innerClass, LAMBDA_INSTANCE_FIELD,
factoryType.returnType()));
} catch (ReflectiveOperationException e) {
throw new LambdaConversionException(
"Exception finding " + LAMBDA_INSTANCE_FIELD + " static field", e);
}
} else {
@SuppressWarnings("removal")
final Constructor<?>[] ctrs = AccessController.doPrivileged(
new PrivilegedAction<>() {
@Override
public Constructor<?>[] run() {
Constructor<?>[] ctrs = innerClass.getDeclaredConstructors();
if (ctrs.length == 1) {
// The lambda implementing inner class constructor is private, set
// it accessible (by us) before creating the constant sole instance
ctrs[0].setAccessible(true);
}
return ctrs;
}
});
if (ctrs.length != 1) {
throw new LambdaConversionException("Expected one lambda constructor for "
+ innerClass.getCanonicalName() + ", got " + ctrs.length);
}

try {
Object inst = ctrs[0].newInstance();
return new ConstantCallSite(MethodHandles.constant(interfaceClass, inst));
} catch (ReflectiveOperationException e) {
throw new LambdaConversionException("Exception instantiating lambda object", e);
}
if (factoryType.parameterCount() == 0 && disableEagerInitialization) {
try {
return new ConstantCallSite(caller.findStaticGetter(innerClass, LAMBDA_INSTANCE_FIELD,
factoryType.returnType()));
} catch (ReflectiveOperationException e) {
throw new LambdaConversionException(
"Exception finding " + LAMBDA_INSTANCE_FIELD + " static field", e);
}
} else {
try {
MethodHandle mh = caller.findConstructor(innerClass, constructorType);
return new ConstantCallSite(mh.asType(factoryType));
if (factoryType.parameterCount() == 0) {
// In the case of a non-capturing lambda, we optimize linkage by pre-computing a single instance
Object inst = mh.asType(methodType(Object.class)).invokeExact();
return new ConstantCallSite(MethodHandles.constant(interfaceClass, inst));
} else {
return new ConstantCallSite(mh.asType(factoryType));
}
} catch (ReflectiveOperationException e) {
throw new LambdaConversionException("Exception finding constructor", e);
} catch (Throwable e) {
throw new LambdaConversionException("Exception instantiating lambda object", e);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;

import static java.lang.invoke.LambdaForm.BasicType;
Expand Down Expand Up @@ -316,7 +317,7 @@ private static String debugString(Object arg) {
* Extract the MemberName of a newly-defined method.
*/
private MemberName loadMethod(byte[] classFile) {
Class<?> invokerClass = LOOKUP.makeHiddenClassDefiner(className, classFile)
Class<?> invokerClass = LOOKUP.makeHiddenClassDefiner(className, classFile, Set.of())
.defineClass(true, classDataValues());
return resolveInvokerMember(invokerClass, invokerName, invokerType);
}
Expand Down Expand Up @@ -376,7 +377,7 @@ static void clinit(ClassWriter cw, String className, List<ClassData> classData)
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_STATIC, "<clinit>", "()V", null, null);
mv.visitCode();
mv.visitLdcInsn(Type.getType("L" + className + ";"));
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/invoke/MethodHandleNatives",
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/invoke/MethodHandles",
"classData", "(Ljava/lang/Class;)Ljava/lang/Object;", false);
// we should optimize one single element case that does not need to create a List
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/util/List");
Expand Down
Loading

1 comment on commit c6339cb

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.