mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8271820: Implementation of JEP 416: Reimplement Core Reflection with 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
This commit is contained in:
parent
5a768f75c9
commit
c6339cb8a2
78 changed files with 6118 additions and 544 deletions
|
@ -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;
|
||||
|
@ -37,7 +36,6 @@ import java.io.FilePermission;
|
|||
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;
|
||||
|
@ -46,8 +44,10 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
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.*;
|
||||
|
||||
/**
|
||||
|
@ -57,7 +57,6 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
|||
* @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>";
|
||||
|
@ -106,7 +105,7 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
|||
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);
|
||||
|
@ -227,50 +226,28 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
|||
@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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ import java.util.ArrayList;
|
|||
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;
|
||||
|
@ -316,7 +317,7 @@ class InvokerBytecodeGenerator {
|
|||
* 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);
|
||||
}
|
||||
|
@ -376,7 +377,7 @@ class InvokerBytecodeGenerator {
|
|||
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");
|
||||
|
|
|
@ -42,6 +42,8 @@ import sun.invoke.util.Wrapper;
|
|||
|
||||
import java.lang.invoke.MethodHandles.Lookup;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
@ -50,6 +52,7 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
@ -57,6 +60,7 @@ import java.util.stream.Stream;
|
|||
import static java.lang.invoke.LambdaForm.*;
|
||||
import static java.lang.invoke.MethodHandleStatics.*;
|
||||
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
||||
|
||||
/**
|
||||
|
@ -1030,6 +1034,7 @@ abstract class MethodHandleImpl {
|
|||
// That way we can lazily load the code and set up the constants.
|
||||
private static class BindCaller {
|
||||
private static MethodType INVOKER_MT = MethodType.methodType(Object.class, MethodHandle.class, Object[].class);
|
||||
private static MethodType REFLECT_INVOKER_MT = MethodType.methodType(Object.class, MethodHandle.class, Object.class, Object[].class);
|
||||
|
||||
static MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) {
|
||||
// Code in the boot layer should now be careful while creating method handles or
|
||||
|
@ -1042,15 +1047,48 @@ abstract class MethodHandleImpl {
|
|||
hostClass.getName().startsWith("java.lang.invoke."))) {
|
||||
throw new InternalError(); // does not happen, and should not anyway
|
||||
}
|
||||
|
||||
MemberName member = mh.internalMemberName();
|
||||
if (member != null) {
|
||||
// Look up the CSM adapter method with the same method name
|
||||
// but with an additional caller class parameter. If present,
|
||||
// bind the adapter's method handle with the lookup class as
|
||||
// the caller class argument
|
||||
MemberName csmAdapter = IMPL_LOOKUP.resolveOrNull(member.getReferenceKind(),
|
||||
new MemberName(member.getDeclaringClass(),
|
||||
member.getName(),
|
||||
member.getMethodType().appendParameterTypes(Class.class),
|
||||
member.getReferenceKind()));
|
||||
if (csmAdapter != null) {
|
||||
assert !csmAdapter.isCallerSensitive();
|
||||
MethodHandle dmh = DirectMethodHandle.make(csmAdapter);
|
||||
dmh = MethodHandles.insertArguments(dmh, dmh.type().parameterCount() - 1, hostClass);
|
||||
dmh = new WrappedMember(dmh, mh.type(), member, mh.isInvokeSpecial(), hostClass);
|
||||
return dmh;
|
||||
}
|
||||
}
|
||||
|
||||
// If no adapter method for CSM with an additional Class parameter
|
||||
// is present, then inject an invoker class that is the caller
|
||||
// invoking the method handle of the CSM
|
||||
try {
|
||||
return bindCallerWithInjectedInvoker(mh, hostClass);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw uncaughtException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static MethodHandle bindCallerWithInjectedInvoker(MethodHandle mh, Class<?> hostClass)
|
||||
throws ReflectiveOperationException
|
||||
{
|
||||
// For simplicity, convert mh to a varargs-like method.
|
||||
MethodHandle vamh = prepareForInvoker(mh);
|
||||
// Cache the result of makeInjectedInvoker once per argument class.
|
||||
MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass);
|
||||
MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass).invoker();
|
||||
return restoreToType(bccInvoker.bindTo(vamh), mh, hostClass);
|
||||
}
|
||||
|
||||
private static MethodHandle makeInjectedInvoker(Class<?> targetClass) {
|
||||
try {
|
||||
private static Class<?> makeInjectedInvoker(Class<?> targetClass) {
|
||||
/*
|
||||
* The invoker class defined to the same class loader as the lookup class
|
||||
* but in an unnamed package so that the class bytes can be cached and
|
||||
|
@ -1064,21 +1102,80 @@ abstract class MethodHandleImpl {
|
|||
name = name.replace('/', '_');
|
||||
}
|
||||
Class<?> invokerClass = new Lookup(targetClass)
|
||||
.makeHiddenClassDefiner(name, INJECTED_INVOKER_TEMPLATE)
|
||||
.defineClass(true);
|
||||
.makeHiddenClassDefiner(name, INJECTED_INVOKER_TEMPLATE, Set.of(NESTMATE))
|
||||
.defineClass(true, targetClass);
|
||||
assert checkInjectedInvoker(targetClass, invokerClass);
|
||||
return IMPL_LOOKUP.findStatic(invokerClass, "invoke_V", INVOKER_MT);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw uncaughtException(ex);
|
||||
}
|
||||
return invokerClass;
|
||||
}
|
||||
|
||||
private static ClassValue<MethodHandle> CV_makeInjectedInvoker = new ClassValue<MethodHandle>() {
|
||||
@Override protected MethodHandle computeValue(Class<?> hostClass) {
|
||||
return makeInjectedInvoker(hostClass);
|
||||
private static ClassValue<InjectedInvokerHolder> CV_makeInjectedInvoker = new ClassValue<>() {
|
||||
@Override
|
||||
protected InjectedInvokerHolder computeValue(Class<?> hostClass) {
|
||||
return new InjectedInvokerHolder(makeInjectedInvoker(hostClass));
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns a method handle of an invoker class injected for reflection
|
||||
* implementation use with the following signature:
|
||||
* reflect_invoke_V(MethodHandle mh, Object target, Object[] args)
|
||||
*
|
||||
* Method::invoke on a caller-sensitive method will call
|
||||
* MethodAccessorImpl::invoke(Object, Object[]) through reflect_invoke_V
|
||||
* target.csm(args)
|
||||
* NativeMethodAccesssorImpl::invoke(target, args)
|
||||
* MethodAccessImpl::invoke(target, args)
|
||||
* InjectedInvoker::reflect_invoke_V(vamh, target, args);
|
||||
* method::invoke(target, args)
|
||||
* p.Foo::m
|
||||
*
|
||||
* An injected invoker class is a hidden class which has the same
|
||||
* defining class loader, runtime package, and protection domain
|
||||
* as the given caller class.
|
||||
*/
|
||||
static MethodHandle reflectiveInvoker(Class<?> caller) {
|
||||
return BindCaller.CV_makeInjectedInvoker.get(caller).reflectInvoker();
|
||||
}
|
||||
|
||||
private static final class InjectedInvokerHolder {
|
||||
private final Class<?> invokerClass;
|
||||
// lazily resolved and cached DMH(s) of invoke_V methods
|
||||
private MethodHandle invoker;
|
||||
private MethodHandle reflectInvoker;
|
||||
|
||||
private InjectedInvokerHolder(Class<?> invokerClass) {
|
||||
this.invokerClass = invokerClass;
|
||||
}
|
||||
|
||||
private MethodHandle invoker() {
|
||||
var mh = invoker;
|
||||
if (mh == null) {
|
||||
try {
|
||||
invoker = mh = IMPL_LOOKUP.findStatic(invokerClass, "invoke_V", INVOKER_MT);
|
||||
} catch (Error | RuntimeException ex) {
|
||||
throw ex;
|
||||
} catch (Throwable ex) {
|
||||
throw new InternalError(ex);
|
||||
}
|
||||
}
|
||||
return mh;
|
||||
}
|
||||
|
||||
private MethodHandle reflectInvoker() {
|
||||
var mh = reflectInvoker;
|
||||
if (mh == null) {
|
||||
try {
|
||||
reflectInvoker = mh = IMPL_LOOKUP.findStatic(invokerClass, "reflect_invoke_V", REFLECT_INVOKER_MT);
|
||||
} catch (Error | RuntimeException ex) {
|
||||
throw ex;
|
||||
} catch (Throwable ex) {
|
||||
throw new InternalError(ex);
|
||||
}
|
||||
}
|
||||
return mh;
|
||||
}
|
||||
}
|
||||
|
||||
// Adapt mh so that it can be called directly from an injected invoker:
|
||||
private static MethodHandle prepareForInvoker(MethodHandle mh) {
|
||||
mh = mh.asFixedArity();
|
||||
|
@ -1115,6 +1212,8 @@ abstract class MethodHandleImpl {
|
|||
MethodHandle invoker = IMPL_LOOKUP.findStatic(invokerClass, "invoke_V", INVOKER_MT);
|
||||
MethodHandle vamh = prepareForInvoker(MH_checkCallerClass);
|
||||
return (boolean)invoker.invoke(vamh, new Object[]{ invokerClass });
|
||||
} catch (Error|RuntimeException ex) {
|
||||
throw ex;
|
||||
} catch (Throwable ex) {
|
||||
throw new InternalError(ex);
|
||||
}
|
||||
|
@ -1151,27 +1250,50 @@ abstract class MethodHandleImpl {
|
|||
ClassWriter cw = new ClassWriter(0);
|
||||
|
||||
// private static class InjectedInvoker {
|
||||
// /* this is used to wrap DMH(s) of caller-sensitive methods */
|
||||
// @Hidden
|
||||
// static Object invoke_V(MethodHandle vamh, Object[] args) throws Throwable {
|
||||
// return vamh.invokeExact(args);
|
||||
// }
|
||||
// /* this is used in caller-sensitive reflective method accessor */
|
||||
// @Hidden
|
||||
// static Object reflect_invoke_V(MethodHandle vamh, Object target, Object[] args) throws Throwable {
|
||||
// return vamh.invokeExact(target, args);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
cw.visit(CLASSFILE_VERSION, ACC_PRIVATE | ACC_SUPER, "InjectedInvoker", null, "java/lang/Object", null);
|
||||
{
|
||||
var mv = cw.visitMethod(ACC_STATIC, "invoke_V",
|
||||
"(Ljava/lang/invoke/MethodHandle;[Ljava/lang/Object;)Ljava/lang/Object;",
|
||||
null, null);
|
||||
|
||||
MethodVisitor mv = cw.visitMethod(ACC_STATIC, "invoke_V",
|
||||
"(Ljava/lang/invoke/MethodHandle;[Ljava/lang/Object;)Ljava/lang/Object;",
|
||||
null, null);
|
||||
mv.visitCode();
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invokeExact",
|
||||
"([Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||
mv.visitInsn(ARETURN);
|
||||
mv.visitMaxs(2, 2);
|
||||
mv.visitEnd();
|
||||
|
||||
mv.visitCode();
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invokeExact",
|
||||
"([Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||
mv.visitInsn(ARETURN);
|
||||
mv.visitMaxs(2, 2);
|
||||
mv.visitEnd();
|
||||
cw.visitEnd();
|
||||
}
|
||||
|
||||
cw.visitEnd();
|
||||
{
|
||||
var mv = cw.visitMethod(ACC_STATIC, "reflect_invoke_V",
|
||||
"(Ljava/lang/invoke/MethodHandle;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;",
|
||||
null, null);
|
||||
mv.visitCode();
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invokeExact",
|
||||
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||
mv.visitInsn(ARETURN);
|
||||
mv.visitMaxs(3, 3);
|
||||
mv.visitEnd();
|
||||
}
|
||||
return cw.toByteArray();
|
||||
}
|
||||
}
|
||||
|
@ -1503,6 +1625,48 @@ abstract class MethodHandleImpl {
|
|||
public VarHandle insertCoordinates(VarHandle target, int pos, Object... values) {
|
||||
return VarHandles.insertCoordinates(target, pos, values);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public MethodHandle unreflectConstructor(Constructor<?> ctor) throws IllegalAccessException {
|
||||
return IMPL_LOOKUP.unreflectConstructor(ctor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodHandle unreflectField(Field field, boolean isSetter) throws IllegalAccessException {
|
||||
return isSetter ? IMPL_LOOKUP.unreflectSetter(field) : IMPL_LOOKUP.unreflectGetter(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodHandle findVirtual(Class<?> defc, String name, MethodType type) throws IllegalAccessException {
|
||||
try {
|
||||
return IMPL_LOOKUP.findVirtual(defc, name, type);
|
||||
} catch (NoSuchMethodException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodHandle findStatic(Class<?> defc, String name, MethodType type) throws IllegalAccessException {
|
||||
try {
|
||||
return IMPL_LOOKUP.findStatic(defc, name, type);
|
||||
} catch (NoSuchMethodException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodHandle reflectiveInvoker(Class<?> caller) {
|
||||
Objects.requireNonNull(caller);
|
||||
return BindCaller.reflectiveInvoker(caller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lookup defineHiddenClassWithClassData(Lookup caller, String name, byte[] bytes, Object classData, boolean initialize) {
|
||||
// skip name and access flags validation
|
||||
return caller.makeHiddenClassDefiner(name, bytes, Set.of()).defineClassAsLookup(initialize, classData);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -25,8 +25,7 @@
|
|||
|
||||
package java.lang.invoke;
|
||||
|
||||
import jdk.internal.access.JavaLangAccess;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.misc.VM;
|
||||
import jdk.internal.ref.CleanerFactory;
|
||||
import sun.invoke.util.Wrapper;
|
||||
|
||||
|
@ -35,7 +34,6 @@ import java.lang.reflect.Field;
|
|||
|
||||
import static java.lang.invoke.MethodHandleNatives.Constants.*;
|
||||
import static java.lang.invoke.MethodHandleStatics.TRACE_METHOD_LINKAGE;
|
||||
import static java.lang.invoke.MethodHandleStatics.UNSAFE;
|
||||
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
|
||||
/**
|
||||
|
@ -248,6 +246,7 @@ class MethodHandleNatives {
|
|||
return true;
|
||||
}
|
||||
static {
|
||||
VM.setJavaLangInvokeInited();
|
||||
assert(verifyConstants());
|
||||
}
|
||||
|
||||
|
@ -665,8 +664,7 @@ class MethodHandleNatives {
|
|||
|
||||
static boolean canBeCalledVirtual(MemberName mem) {
|
||||
assert(mem.isInvocable());
|
||||
return mem.getName().equals("getContextClassLoader") &&
|
||||
canBeCalledVirtual(mem, java.lang.Thread.class);
|
||||
return mem.getName().equals("getContextClassLoader") && canBeCalledVirtual(mem, java.lang.Thread.class);
|
||||
}
|
||||
|
||||
static boolean canBeCalledVirtual(MemberName symbolicRef, Class<?> definingClass) {
|
||||
|
@ -676,16 +674,4 @@ class MethodHandleNatives {
|
|||
return (definingClass.isAssignableFrom(symbolicRefClass) || // Msym overrides Mdef
|
||||
symbolicRefClass.isInterface()); // Mdef implements Msym
|
||||
}
|
||||
|
||||
private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
|
||||
/*
|
||||
* Returns the class data set by the VM in the Class::classData field.
|
||||
*
|
||||
* This is also invoked by LambdaForms as it cannot use condy via
|
||||
* MethodHandles.classData due to bootstrapping issue.
|
||||
*/
|
||||
static Object classData(Class<?> c) {
|
||||
UNSAFE.ensureClassInitialized(c);
|
||||
return JLA.classData(c);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import jdk.internal.org.objectweb.asm.ClassReader;
|
|||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.Type;
|
||||
import jdk.internal.reflect.CallerSensitive;
|
||||
import jdk.internal.reflect.CallerSensitiveAdapter;
|
||||
import jdk.internal.reflect.Reflection;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
import sun.invoke.util.ValueConversions;
|
||||
|
@ -63,7 +64,9 @@ import java.util.stream.Stream;
|
|||
import static java.lang.invoke.LambdaForm.BasicType.V_TYPE;
|
||||
import static java.lang.invoke.MethodHandleImpl.Intrinsic;
|
||||
import static java.lang.invoke.MethodHandleNatives.Constants.*;
|
||||
import static java.lang.invoke.MethodHandleStatics.UNSAFE;
|
||||
import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException;
|
||||
import static java.lang.invoke.MethodHandleStatics.newInternalError;
|
||||
import static java.lang.invoke.MethodType.methodType;
|
||||
|
||||
/**
|
||||
|
@ -117,14 +120,15 @@ public class MethodHandles {
|
|||
}
|
||||
|
||||
/**
|
||||
* This reflected$lookup method is the alternate implementation of
|
||||
* the lookup method when being invoked by reflection.
|
||||
* This lookup method is the alternate implementation of
|
||||
* the lookup method with a leading caller class argument which is
|
||||
* non-caller-sensitive. This method is only invoked by reflection
|
||||
* and method handle.
|
||||
*/
|
||||
@CallerSensitive
|
||||
private static Lookup reflected$lookup() {
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
@CallerSensitiveAdapter
|
||||
private static Lookup lookup(Class<?> caller) {
|
||||
if (caller.getClassLoader() == null) {
|
||||
throw newIllegalArgumentException("illegal lookupClass: "+caller);
|
||||
throw newInternalError("calling lookup() reflectively is not supported: "+caller);
|
||||
}
|
||||
return new Lookup(caller);
|
||||
}
|
||||
|
@ -329,7 +333,7 @@ public class MethodHandles {
|
|||
throw new IllegalAccessException(caller + " does not have ORIGINAL access");
|
||||
}
|
||||
|
||||
Object classdata = MethodHandleNatives.classData(caller.lookupClass());
|
||||
Object classdata = classData(caller.lookupClass());
|
||||
if (classdata == null) return null;
|
||||
|
||||
try {
|
||||
|
@ -341,6 +345,17 @@ public class MethodHandles {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the class data set by the VM in the Class::classData field.
|
||||
*
|
||||
* This is also invoked by LambdaForms as it cannot use condy via
|
||||
* MethodHandles::classData due to bootstrapping issue.
|
||||
*/
|
||||
static Object classData(Class<?> c) {
|
||||
UNSAFE.ensureClassInitialized(c);
|
||||
return SharedSecrets.getJavaLangAccess().classData(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the element at the specified index in the
|
||||
* {@linkplain #classData(Lookup, String, Class) class data},
|
||||
|
@ -2359,15 +2374,16 @@ public class MethodHandles {
|
|||
|
||||
/**
|
||||
* Returns a ClassDefiner that creates a {@code Class} object of a hidden class
|
||||
* from the given bytes. No package name check on the given name.
|
||||
* from the given bytes and the given options. No package name check on the given name.
|
||||
*
|
||||
* @param name fully-qualified name that specifies the prefix of the hidden class
|
||||
* @param bytes class bytes
|
||||
* @return ClassDefiner that defines a hidden class of the given bytes.
|
||||
* @param options class options
|
||||
* @return ClassDefiner that defines a hidden class of the given bytes and options.
|
||||
*/
|
||||
ClassDefiner makeHiddenClassDefiner(String name, byte[] bytes) {
|
||||
ClassDefiner makeHiddenClassDefiner(String name, byte[] bytes, Set<ClassOption> options) {
|
||||
// skip name and access flags validation
|
||||
return makeHiddenClassDefiner(ClassFile.newInstanceNoCheck(name, bytes), Set.of(), false);
|
||||
return makeHiddenClassDefiner(ClassFile.newInstanceNoCheck(name, bytes), options, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue