提交 2e5b7b7f 编写于 作者: C chegar

8017044: anti-delta fix for 8015402

Reviewed-by: alanb
上级 0a85f8ea
...@@ -24,11 +24,14 @@ ...@@ -24,11 +24,14 @@
*/ */
package java.lang.invoke; package java.lang.invoke;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import sun.invoke.util.Wrapper; import sun.invoke.util.Wrapper;
import static sun.invoke.util.Wrapper.*;
import static sun.invoke.util.Wrapper.forPrimitiveType;
import static sun.invoke.util.Wrapper.forWrapperType;
import static sun.invoke.util.Wrapper.isWrapperType;
/** /**
* Abstract implementation of a lambda metafactory which provides parameter unrolling and input validation. * Abstract implementation of a lambda metafactory which provides parameter unrolling and input validation.
...@@ -64,52 +67,34 @@ import static sun.invoke.util.Wrapper.isWrapperType; ...@@ -64,52 +67,34 @@ import static sun.invoke.util.Wrapper.isWrapperType;
final MethodType instantiatedMethodType; // Instantiated erased functional interface method type "(Integer)Object" final MethodType instantiatedMethodType; // Instantiated erased functional interface method type "(Integer)Object"
final boolean isSerializable; // Should the returned instance be serializable final boolean isSerializable; // Should the returned instance be serializable
final Class<?>[] markerInterfaces; // Additional marker interfaces to be implemented final Class<?>[] markerInterfaces; // Additional marker interfaces to be implemented
final MethodType[] additionalBridges; // Signatures of additional methods to bridge
/** /**
* Meta-factory constructor. * Meta-factory constructor.
* *
* @param caller Stacked automatically by VM; represents a lookup context * @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges
* with the accessibility privileges of the caller. * of the caller.
* @param invokedType Stacked automatically by VM; the signature of the * @param invokedType Stacked automatically by VM; the signature of the invoked method, which includes the
* invoked method, which includes the expected static * expected static type of the returned lambda object, and the static types of the captured
* type of the returned lambda object, and the static * arguments for the lambda. In the event that the implementation method is an instance method,
* types of the captured arguments for the lambda. In * the first argument in the invocation signature will correspond to the receiver.
* the event that the implementation method is an * @param samMethod The primary method in the functional interface to which the lambda or method reference is
* instance method, the first argument in the invocation * being converted, represented as a method handle.
* signature will correspond to the receiver. * @param implMethod The implementation method which should be called (with suitable adaptation of argument
* @param samMethod The primary method in the functional interface to which * types, return types, and adjustment for captured arguments) when methods of the resulting
* the lambda or method reference is being converted, * functional interface instance are invoked.
* represented as a method handle. * @param instantiatedMethodType The signature of the primary functional interface method after type variables
* @param implMethod The implementation method which should be called * are substituted with their instantiation from the capture site
* (with suitable adaptation of argument types, return
* types, and adjustment for captured arguments) when
* methods of the resulting functional interface instance
* are invoked.
* @param instantiatedMethodType The signature of the primary functional
* interface method after type variables are
* substituted with their instantiation from
* the capture site
* @param isSerializable Should the lambda be made serializable? If set,
* either the target type or one of the additional SAM
* types must extend {@code Serializable}.
* @param markerInterfaces Additional interfaces which the lambda object
* should implement.
* @param additionalBridges Method types for additional signatures to be
* bridged to the implementation method
* @throws ReflectiveOperationException * @throws ReflectiveOperationException
* @throws LambdaConversionException If any of the meta-factory protocol * @throws LambdaConversionException If any of the meta-factory protocol invariants are violated
* invariants are violated
*/ */
AbstractValidatingLambdaMetafactory(MethodHandles.Lookup caller, AbstractValidatingLambdaMetafactory(MethodHandles.Lookup caller,
MethodType invokedType, MethodType invokedType,
MethodHandle samMethod, MethodHandle samMethod,
MethodHandle implMethod, MethodHandle implMethod,
MethodType instantiatedMethodType, MethodType instantiatedMethodType,
boolean isSerializable, int flags,
Class<?>[] markerInterfaces, Class<?>[] markerInterfaces)
MethodType[] additionalBridges)
throws ReflectiveOperationException, LambdaConversionException { throws ReflectiveOperationException, LambdaConversionException {
this.targetClass = caller.lookupClass(); this.targetClass = caller.lookupClass();
this.invokedType = invokedType; this.invokedType = invokedType;
...@@ -133,22 +118,32 @@ import static sun.invoke.util.Wrapper.isWrapperType; ...@@ -133,22 +118,32 @@ import static sun.invoke.util.Wrapper.isWrapperType;
implKind == MethodHandleInfo.REF_invokeInterface; implKind == MethodHandleInfo.REF_invokeInterface;
this.implDefiningClass = implInfo.getDeclaringClass(); this.implDefiningClass = implInfo.getDeclaringClass();
this.implMethodType = implInfo.getMethodType(); this.implMethodType = implInfo.getMethodType();
this.instantiatedMethodType = instantiatedMethodType; this.instantiatedMethodType = instantiatedMethodType;
this.isSerializable = isSerializable;
this.markerInterfaces = markerInterfaces;
this.additionalBridges = additionalBridges;
if (!samClass.isInterface()) { if (!samClass.isInterface()) {
throw new LambdaConversionException(String.format( throw new LambdaConversionException(String.format(
"Functional interface %s is not an interface", samClass.getName())); "Functional interface %s is not an interface",
samClass.getName()));
} }
boolean foundSerializableSupertype = Serializable.class.isAssignableFrom(samBase);
for (Class<?> c : markerInterfaces) { for (Class<?> c : markerInterfaces) {
if (!c.isInterface()) { if (!c.isInterface()) {
throw new LambdaConversionException(String.format( throw new LambdaConversionException(String.format(
"Marker interface %s is not an interface", c.getName())); "Marker interface %s is not an interface",
c.getName()));
} }
foundSerializableSupertype |= Serializable.class.isAssignableFrom(c);
} }
this.isSerializable = ((flags & LambdaMetafactory.FLAG_SERIALIZABLE) != 0)
|| foundSerializableSupertype;
if (isSerializable && !foundSerializableSupertype) {
markerInterfaces = Arrays.copyOf(markerInterfaces, markerInterfaces.length + 1);
markerInterfaces[markerInterfaces.length-1] = Serializable.class;
}
this.markerInterfaces = markerInterfaces;
} }
/** /**
...@@ -270,9 +265,9 @@ import static sun.invoke.util.Wrapper.isWrapperType; ...@@ -270,9 +265,9 @@ import static sun.invoke.util.Wrapper.isWrapperType;
} }
/** /**
* Check type adaptability for parameter types. * Check type adaptability
* @param fromType Type to convert from * @param fromType
* @param toType Type to convert to * @param toType
* @param strict If true, do strict checks, else allow that fromType may be parameterized * @param strict If true, do strict checks, else allow that fromType may be parameterized
* @return True if 'fromType' can be passed to an argument of 'toType' * @return True if 'fromType' can be passed to an argument of 'toType'
*/ */
...@@ -304,14 +299,15 @@ import static sun.invoke.util.Wrapper.isWrapperType; ...@@ -304,14 +299,15 @@ import static sun.invoke.util.Wrapper.isWrapperType;
} }
} else { } else {
// both are reference types: fromType should be a superclass of toType. // both are reference types: fromType should be a superclass of toType.
return !strict || toType.isAssignableFrom(fromType); return strict? toType.isAssignableFrom(fromType) : true;
} }
} }
} }
/** /**
* Check type adaptability for return types -- special handling of void type) * Check type adaptability for return types -- special handling of void type) and parameterized fromType
* and parameterized fromType * @param fromType
* @param toType
* @return True if 'fromType' can be converted to 'toType' * @return True if 'fromType' can be converted to 'toType'
*/ */
private boolean isAdaptableToAsReturn(Class<?> fromType, Class<?> toType) { private boolean isAdaptableToAsReturn(Class<?> fromType, Class<?> toType) {
...@@ -342,4 +338,89 @@ import static sun.invoke.util.Wrapper.isWrapperType; ...@@ -342,4 +338,89 @@ import static sun.invoke.util.Wrapper.isWrapperType;
} }
***********************/ ***********************/
/**
* Find the functional interface method and corresponding abstract methods
* which should be bridged. The functional interface method and those to be
* bridged will have the same name and number of parameters. Check for
* matching default methods (non-abstract), the VM will create bridges for
* default methods; We don't have enough readily available type information
* to distinguish between where the functional interface method should be
* bridged and where the default method should be bridged; This situation is
* flagged.
*/
class MethodAnalyzer {
private final Method[] methods = samBase.getMethods();
private Method samMethod = null;
private final List<Method> methodsToBridge = new ArrayList<>(methods.length);
private boolean conflictFoundBetweenDefaultAndBridge = false;
MethodAnalyzer() {
String samMethodName = samInfo.getName();
Class<?>[] samParamTypes = samMethodType.parameterArray();
int samParamLength = samParamTypes.length;
Class<?> samReturnType = samMethodType.returnType();
Class<?> objectClass = Object.class;
List<Method> defaultMethods = new ArrayList<>(methods.length);
for (Method m : methods) {
if (m.getName().equals(samMethodName) && m.getDeclaringClass() != objectClass) {
Class<?>[] mParamTypes = m.getParameterTypes();
if (mParamTypes.length == samParamLength) {
// Method matches name and parameter length -- and is not Object
if (Modifier.isAbstract(m.getModifiers())) {
// Method is abstract
if (m.getReturnType().equals(samReturnType)
&& Arrays.equals(mParamTypes, samParamTypes)) {
// Exact match, this is the SAM method signature
samMethod = m;
} else if (!hasMatchingBridgeSignature(m)) {
// Record bridges, exclude methods with duplicate signatures
methodsToBridge.add(m);
}
} else {
// Record default methods for conflict testing
defaultMethods.add(m);
}
}
}
}
for (Method dm : defaultMethods) {
if (hasMatchingBridgeSignature(dm)) {
conflictFoundBetweenDefaultAndBridge = true;
break;
}
}
}
Method getSamMethod() {
return samMethod;
}
List<Method> getMethodsToBridge() {
return methodsToBridge;
}
boolean conflictFoundBetweenDefaultAndBridge() {
return conflictFoundBetweenDefaultAndBridge;
}
/**
* Search the list of previously found bridge methods to determine if there is a method with the same signature
* (return and parameter types) as the specified method.
*
* @param m The method to match
* @return True if the method was found, False otherwise
*/
private boolean hasMatchingBridgeSignature(Method m) {
Class<?>[] ptypes = m.getParameterTypes();
Class<?> rtype = m.getReturnType();
for (Method md : methodsToBridge) {
if (md.getReturnType().equals(rtype) && Arrays.equals(ptypes, md.getParameterTypes())) {
return true;
}
}
return false;
}
}
} }
...@@ -25,16 +25,15 @@ ...@@ -25,16 +25,15 @@
package java.lang.invoke; package java.lang.invoke;
import jdk.internal.org.objectweb.asm.*;
import sun.misc.Unsafe;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.security.AccessController; import java.lang.reflect.Method;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain; import java.security.ProtectionDomain;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import jdk.internal.org.objectweb.asm.*;
import static jdk.internal.org.objectweb.asm.Opcodes.*; import static jdk.internal.org.objectweb.asm.Opcodes.*;
import sun.misc.Unsafe;
import java.security.AccessController;
import java.security.PrivilegedAction;
/** /**
* Lambda metafactory implementation which dynamically creates an inner-class-like class per lambda callsite. * Lambda metafactory implementation which dynamically creates an inner-class-like class per lambda callsite.
...@@ -42,8 +41,6 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; ...@@ -42,8 +41,6 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
* @see LambdaMetafactory * @see LambdaMetafactory
*/ */
/* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory { /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
private static final int CLASSFILE_VERSION = 51; private static final int CLASSFILE_VERSION = 51;
private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE); private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
private static final String NAME_MAGIC_ACCESSOR_IMPL = "java/lang/invoke/MagicLambdaImpl"; private static final String NAME_MAGIC_ACCESSOR_IMPL = "java/lang/invoke/MagicLambdaImpl";
...@@ -80,51 +77,36 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; ...@@ -80,51 +77,36 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
private final Type[] instantiatedArgumentTypes; // ASM types for the functional interface arguments private final Type[] instantiatedArgumentTypes; // ASM types for the functional interface arguments
/** /**
* General meta-factory constructor, supporting both standard cases and * General meta-factory constructor, standard cases and allowing for uncommon options such as serialization.
* allowing for uncommon options such as serialization or bridging.
* *
* @param caller Stacked automatically by VM; represents a lookup context * @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges
* with the accessibility privileges of the caller. * of the caller.
* @param invokedType Stacked automatically by VM; the signature of the * @param invokedType Stacked automatically by VM; the signature of the invoked method, which includes the
* invoked method, which includes the expected static * expected static type of the returned lambda object, and the static types of the captured
* type of the returned lambda object, and the static * arguments for the lambda. In the event that the implementation method is an instance method,
* types of the captured arguments for the lambda. In * the first argument in the invocation signature will correspond to the receiver.
* the event that the implementation method is an * @param samMethod The primary method in the functional interface to which the lambda or method reference is
* instance method, the first argument in the invocation * being converted, represented as a method handle.
* signature will correspond to the receiver. * @param implMethod The implementation method which should be called (with suitable adaptation of argument
* @param samMethod The primary method in the functional interface to which * types, return types, and adjustment for captured arguments) when methods of the resulting
* the lambda or method reference is being converted, * functional interface instance are invoked.
* represented as a method handle. * @param instantiatedMethodType The signature of the primary functional interface method after type variables
* @param implMethod The implementation method which should be called (with * are substituted with their instantiation from the capture site
* suitable adaptation of argument types, return types, * @param flags A bitmask containing flags that may influence the translation of this lambda expression. Defined
* and adjustment for captured arguments) when methods of * fields include FLAG_SERIALIZABLE.
* the resulting functional interface instance are invoked. * @param markerInterfaces Additional interfaces which the lambda object should implement.
* @param instantiatedMethodType The signature of the primary functional
* interface method after type variables are
* substituted with their instantiation from
* the capture site
* @param isSerializable Should the lambda be made serializable? If set,
* either the target type or one of the additional SAM
* types must extend {@code Serializable}.
* @param markerInterfaces Additional interfaces which the lambda object
* should implement.
* @param additionalBridges Method types for additional signatures to be
* bridged to the implementation method
* @throws ReflectiveOperationException * @throws ReflectiveOperationException
* @throws LambdaConversionException If any of the meta-factory protocol * @throws LambdaConversionException If any of the meta-factory protocol invariants are violated
* invariants are violated
*/ */
public InnerClassLambdaMetafactory(MethodHandles.Lookup caller, public InnerClassLambdaMetafactory(MethodHandles.Lookup caller,
MethodType invokedType, MethodType invokedType,
MethodHandle samMethod, MethodHandle samMethod,
MethodHandle implMethod, MethodHandle implMethod,
MethodType instantiatedMethodType, MethodType instantiatedMethodType,
boolean isSerializable, int flags,
Class<?>[] markerInterfaces, Class<?>[] markerInterfaces)
MethodType[] additionalBridges)
throws ReflectiveOperationException, LambdaConversionException { throws ReflectiveOperationException, LambdaConversionException {
super(caller, invokedType, samMethod, implMethod, instantiatedMethodType, super(caller, invokedType, samMethod, implMethod, instantiatedMethodType, flags, markerInterfaces);
isSerializable, markerInterfaces, additionalBridges);
implMethodClassName = implDefiningClass.getName().replace('.', '/'); implMethodClassName = implDefiningClass.getName().replace('.', '/');
implMethodName = implInfo.getName(); implMethodName = implInfo.getName();
implMethodDesc = implMethodType.toMethodDescriptorString(); implMethodDesc = implMethodType.toMethodDescriptorString();
...@@ -152,8 +134,7 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; ...@@ -152,8 +134,7 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
* @return a CallSite, which, when invoked, will return an instance of the * @return a CallSite, which, when invoked, will return an instance of the
* functional interface * functional interface
* @throws ReflectiveOperationException * @throws ReflectiveOperationException
* @throws LambdaConversionException If properly formed functional interface * @throws LambdaConversionException If properly formed functional interface is not found
* is not found
*/ */
@Override @Override
CallSite buildCallSite() throws ReflectiveOperationException, LambdaConversionException { CallSite buildCallSite() throws ReflectiveOperationException, LambdaConversionException {
...@@ -193,16 +174,8 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; ...@@ -193,16 +174,8 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
* Generate a class file which implements the functional * Generate a class file which implements the functional
* interface, define and return the class. * interface, define and return the class.
* *
* @implNote The class that is generated does not include signature
* information for exceptions that may be present on the SAM method.
* This is to reduce classfile size, and is harmless as checked exceptions
* are erased anyway, no one will ever compile against this classfile,
* and we make no guarantees about the reflective properties of lambda
* objects.
*
* @return a Class which implements the functional interface * @return a Class which implements the functional interface
* @throws LambdaConversionException If properly formed functional interface * @throws LambdaConversionException If properly formed functional interface is not found
* is not found
*/ */
private Class<?> spinInnerClass() throws LambdaConversionException { private Class<?> spinInnerClass() throws LambdaConversionException {
String samName = samBase.getName().replace('.', '/'); String samName = samBase.getName().replace('.', '/');
...@@ -224,22 +197,28 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; ...@@ -224,22 +197,28 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
generateConstructor(); generateConstructor();
MethodAnalyzer ma = new MethodAnalyzer();
// Forward the SAM method // Forward the SAM method
String methodDescriptor = samMethodType.toMethodDescriptorString(); if (ma.getSamMethod() == null) {
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samInfo.getName(), methodDescriptor, null, null); throw new LambdaConversionException(String.format("Functional interface method not found: %s", samMethodType));
new ForwardingMethodGenerator(mv).generate(methodDescriptor); } else {
generateForwardingMethod(ma.getSamMethod(), false);
}
// Forward the bridges // Forward the bridges
if (additionalBridges != null) { // @@@ The commented-out code is temporary, pending the VM's ability to bridge all methods on request
for (MethodType mt : additionalBridges) { // @@@ Once the VM can do fail-over, uncomment the !ma.wasDefaultMethodFound() test, and emit the appropriate
methodDescriptor = mt.toMethodDescriptorString(); // @@@ classfile attribute to request custom bridging. See 8002092.
mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samInfo.getName(), methodDescriptor, null, null); if (!ma.getMethodsToBridge().isEmpty() /* && !ma.conflictFoundBetweenDefaultAndBridge() */ ) {
new ForwardingMethodGenerator(mv).generate(methodDescriptor); for (Method m : ma.getMethodsToBridge()) {
generateForwardingMethod(m, true);
} }
} }
if (isSerializable) if (isSerializable) {
generateWriteReplace(); generateWriteReplace();
}
cw.visitEnd(); cw.visitEnd();
...@@ -268,8 +247,8 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; ...@@ -268,8 +247,8 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
} }
); );
return UNSAFE.defineClass(lambdaClassName, classBytes, 0, classBytes.length, return (Class<?>) Unsafe.getUnsafe().defineClass(lambdaClassName, classBytes, 0, classBytes.length,
loader, pd); loader, pd);
} }
/** /**
...@@ -286,8 +265,7 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; ...@@ -286,8 +265,7 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
ctor.visitVarInsn(ALOAD, 0); ctor.visitVarInsn(ALOAD, 0);
ctor.visitVarInsn(argTypes[i].getOpcode(ILOAD), lvIndex + 1); ctor.visitVarInsn(argTypes[i].getOpcode(ILOAD), lvIndex + 1);
lvIndex += argTypes[i].getSize(); lvIndex += argTypes[i].getSize();
ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor());
argTypes[i].getDescriptor());
} }
ctor.visitInsn(RETURN); ctor.visitInsn(RETURN);
ctor.visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored ctor.visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
...@@ -305,7 +283,7 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; ...@@ -305,7 +283,7 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
mv.visitCode(); mv.visitCode();
mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA); mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA);
mv.visitInsn(DUP); mv.visitInsn(DUP);;
mv.visitLdcInsn(Type.getType(targetClass)); mv.visitLdcInsn(Type.getType(targetClass));
mv.visitLdcInsn(samInfo.getReferenceKind()); mv.visitLdcInsn(samInfo.getReferenceKind());
mv.visitLdcInsn(invokedType.returnType().getName().replace('.', '/')); mv.visitLdcInsn(invokedType.returnType().getName().replace('.', '/'));
...@@ -334,6 +312,24 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; ...@@ -334,6 +312,24 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
mv.visitEnd(); mv.visitEnd();
} }
/**
* Generate a method which calls the lambda implementation method,
* converting arguments, as needed.
* @param m The method whose signature should be generated
* @param isBridge True if this methods should be flagged as a bridge
*/
private void generateForwardingMethod(Method m, boolean isBridge) {
Class<?>[] exceptionTypes = m.getExceptionTypes();
String[] exceptionNames = new String[exceptionTypes.length];
for (int i = 0; i < exceptionTypes.length; i++) {
exceptionNames[i] = exceptionTypes[i].getName().replace('.', '/');
}
String methodDescriptor = Type.getMethodDescriptor(m);
int access = isBridge? ACC_PUBLIC | ACC_BRIDGE : ACC_PUBLIC;
MethodVisitor mv = cw.visitMethod(access, m.getName(), methodDescriptor, null, exceptionNames);
new ForwardingMethodGenerator(mv).generate(m);
}
/** /**
* This class generates a method body which calls the lambda implementation * This class generates a method body which calls the lambda implementation
* method, converting arguments, as needed. * method, converting arguments, as needed.
...@@ -344,26 +340,26 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; ...@@ -344,26 +340,26 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
super(mv); super(mv);
} }
void generate(String methodDescriptor) { void generate(Method m) throws InternalError {
visitCode(); visitCode();
if (implKind == MethodHandleInfo.REF_newInvokeSpecial) { if (implKind == MethodHandleInfo.REF_newInvokeSpecial) {
visitTypeInsn(NEW, implMethodClassName); visitTypeInsn(NEW, implMethodClassName);
visitInsn(DUP); visitInsn(DUP);;
} }
for (int i = 0; i < argTypes.length; i++) { for (int i = 0; i < argTypes.length; i++) {
visitVarInsn(ALOAD, 0); visitVarInsn(ALOAD, 0);
visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor()); visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor());
} }
convertArgumentTypes(Type.getArgumentTypes(methodDescriptor)); convertArgumentTypes(Type.getArgumentTypes(m));
// Invoke the method we want to forward to // Invoke the method we want to forward to
visitMethodInsn(invocationOpcode(), implMethodClassName, implMethodName, implMethodDesc); visitMethodInsn(invocationOpcode(), implMethodClassName, implMethodName, implMethodDesc);
// Convert the return value (if any) and return it // Convert the return value (if any) and return it
// Note: if adapting from non-void to void, the 'return' instruction will pop the unneeded result // Note: if adapting from non-void to void, the 'return' instruction will pop the unneeded result
Type samReturnType = Type.getReturnType(methodDescriptor); Type samReturnType = Type.getReturnType(m);
convertType(implMethodReturnType, samReturnType, samReturnType); convertType(implMethodReturnType, samReturnType, samReturnType);
visitInsn(samReturnType.getOpcode(Opcodes.IRETURN)); visitInsn(samReturnType.getOpcode(Opcodes.IRETURN));
......
...@@ -25,9 +25,6 @@ ...@@ -25,9 +25,6 @@
package java.lang.invoke; package java.lang.invoke;
import java.io.Serializable;
import java.util.Arrays;
/** /**
* <p>Bootstrap methods for converting lambda expressions and method references to functional interface objects.</p> * <p>Bootstrap methods for converting lambda expressions and method references to functional interface objects.</p>
* *
...@@ -47,11 +44,16 @@ import java.util.Arrays; ...@@ -47,11 +44,16 @@ import java.util.Arrays;
* *
* <p>When parameterized types are used, the instantiated type of the functional interface method may be different * <p>When parameterized types are used, the instantiated type of the functional interface method may be different
* from that in the functional interface. For example, consider * from that in the functional interface. For example, consider
* {@code interface I<T> { int m(T x); }} if this functional interface type is used in a lambda * <code>interface I&lt;T&gt; { int m(T x); }</code> if this functional interface type is used in a lambda
* {@code I<Byte>; v = ...}, we need both the actual functional interface method which has the signature * <code>I&lt;Byte&gt; v = ...</code>, we need both the actual functional interface method which has the signature
* {@code (Object)int} and the erased instantiated type of the functional interface method (or simply * <code>(Object)int</code> and the erased instantiated type of the functional interface method (or simply
* <I>instantiated method type</I>), which has signature * <I>instantiated method type</I>), which has signature
* {@code (Byte)int}. * <code>(Byte)int</code>.
*
* <p>While functional interfaces only have a single abstract method from the language perspective (concrete
* methods in Object are and default methods may be present), at the bytecode level they may actually have multiple
* methods because of the need for bridge methods. Invoking any of these methods on the lambda object will result
* in invoking the implementation method.
* *
* <p>The argument list of the implementation method and the argument list of the functional interface method(s) * <p>The argument list of the implementation method and the argument list of the functional interface method(s)
* may differ in several ways. The implementation methods may have additional arguments to accommodate arguments * may differ in several ways. The implementation methods may have additional arguments to accommodate arguments
...@@ -142,59 +144,38 @@ import java.util.Arrays; ...@@ -142,59 +144,38 @@ import java.util.Arrays;
*/ */
public class LambdaMetafactory { public class LambdaMetafactory {
/** Flag for alternate metafactories indicating the lambda object is /** Flag for alternate metafactories indicating the lambda object is must to be serializable */
* must to be serializable */
public static final int FLAG_SERIALIZABLE = 1 << 0; public static final int FLAG_SERIALIZABLE = 1 << 0;
/** /**
* Flag for alternate metafactories indicating the lambda object implements * Flag for alternate metafactories indicating the lambda object implements other marker interfaces
* other marker interfaces
* besides Serializable * besides Serializable
*/ */
public static final int FLAG_MARKERS = 1 << 1; public static final int FLAG_MARKERS = 1 << 1;
/**
* Flag for alternate metafactories indicating the lambda object requires
* additional bridge methods
*/
public static final int FLAG_BRIDGES = 1 << 2;
private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0]; private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
private static final MethodType[] EMPTY_MT_ARRAY = new MethodType[0];
/** /**
* Standard meta-factory for conversion of lambda expressions or method * Standard meta-factory for conversion of lambda expressions or method references to functional interfaces.
* references to functional interfaces.
* *
* @param caller Stacked automatically by VM; represents a lookup context * @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges
* with the accessibility privileges of the caller. * of the caller.
* @param invokedName Stacked automatically by VM; the name of the invoked * @param invokedName Stacked automatically by VM; the name of the invoked method as it appears at the call site.
* method as it appears at the call site.
* Currently unused. * Currently unused.
* @param invokedType Stacked automatically by VM; the signature of the * @param invokedType Stacked automatically by VM; the signature of the invoked method, which includes the
* invoked method, which includes the expected static * expected static type of the returned lambda object, and the static types of the captured
* type of the returned lambda object, and the static * arguments for the lambda. In the event that the implementation method is an instance method,
* types of the captured arguments for the lambda. * the first argument in the invocation signature will correspond to the receiver.
* In the event that the implementation method is an * @param samMethod The primary method in the functional interface to which the lambda or method reference is
* instance method, the first argument in the invocation * being converted, represented as a method handle.
* signature will correspond to the receiver. * @param implMethod The implementation method which should be called (with suitable adaptation of argument
* @param samMethod The primary method in the functional interface to which * types, return types, and adjustment for captured arguments) when methods of the resulting
* the lambda or method reference is being converted, * functional interface instance are invoked.
* represented as a method handle. * @param instantiatedMethodType The signature of the primary functional interface method after type variables
* @param implMethod The implementation method which should be called * are substituted with their instantiation from the capture site
* (with suitable adaptation of argument types, return * @return a CallSite, which, when invoked, will return an instance of the functional interface
* types, and adjustment for captured arguments) when
* methods of the resulting functional interface instance
* are invoked.
* @param instantiatedMethodType The signature of the primary functional
* interface method after type variables
* are substituted with their instantiation
* from the capture site
* @return a CallSite, which, when invoked, will return an instance of the
* functional interface
* @throws ReflectiveOperationException * @throws ReflectiveOperationException
* @throws LambdaConversionException If any of the meta-factory protocol * @throws LambdaConversionException If any of the meta-factory protocol invariants are violated
* invariants are violated
*/ */
public static CallSite metaFactory(MethodHandles.Lookup caller, public static CallSite metaFactory(MethodHandles.Lookup caller,
String invokedName, String invokedName,
...@@ -204,17 +185,15 @@ public class LambdaMetafactory { ...@@ -204,17 +185,15 @@ public class LambdaMetafactory {
MethodType instantiatedMethodType) MethodType instantiatedMethodType)
throws ReflectiveOperationException, LambdaConversionException { throws ReflectiveOperationException, LambdaConversionException {
AbstractValidatingLambdaMetafactory mf; AbstractValidatingLambdaMetafactory mf;
mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod, mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod, implMethod, instantiatedMethodType,
implMethod, instantiatedMethodType, 0, EMPTY_CLASS_ARRAY);
false, EMPTY_CLASS_ARRAY, EMPTY_MT_ARRAY);
mf.validateMetafactoryArgs(); mf.validateMetafactoryArgs();
return mf.buildCallSite(); return mf.buildCallSite();
} }
/** /**
* Alternate meta-factory for conversion of lambda expressions or method * Alternate meta-factory for conversion of lambda expressions or method references to functional interfaces,
* references to functional interfaces, which supports serialization and * which supports serialization and other uncommon options.
* other uncommon options.
* *
* The declared argument list for this method is: * The declared argument list for this method is:
* *
...@@ -234,28 +213,21 @@ public class LambdaMetafactory { ...@@ -234,28 +213,21 @@ public class LambdaMetafactory {
* int flags, * int flags,
* int markerInterfaceCount, // IF flags has MARKERS set * int markerInterfaceCount, // IF flags has MARKERS set
* Class... markerInterfaces // IF flags has MARKERS set * Class... markerInterfaces // IF flags has MARKERS set
* int bridgeCount, // IF flags has BRIDGES set
* MethodType... bridges // IF flags has BRIDGES set
* ) * )
* *
* *
* @param caller Stacked automatically by VM; represents a lookup context * @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges
* with the accessibility privileges of the caller. * of the caller.
* @param invokedName Stacked automatically by VM; the name of the invoked * @param invokedName Stacked automatically by VM; the name of the invoked method as it appears at the call site.
* method as it appears at the call site. Currently unused. * Currently unused.
* @param invokedType Stacked automatically by VM; the signature of the * @param invokedType Stacked automatically by VM; the signature of the invoked method, which includes thefu
* invoked method, which includes the expected static * expected static type of the returned lambda object, and the static types of the captured
* type of the returned lambda object, and the static * arguments for the lambda. In the event that the implementation method is an instance method,
* types of the captured arguments for the lambda. * the first argument in the invocation signature will correspond to the receiver.
* In the event that the implementation method is an * @param args argument to pass, flags, marker interface count, and marker interfaces as described above
* instance method, the first argument in the invocation * @return a CallSite, which, when invoked, will return an instance of the functional interface
* signature will correspond to the receiver.
* @param args flags and optional arguments, as described above
* @return a CallSite, which, when invoked, will return an instance of the
* functional interface
* @throws ReflectiveOperationException * @throws ReflectiveOperationException
* @throws LambdaConversionException If any of the meta-factory protocol * @throws LambdaConversionException If any of the meta-factory protocol invariants are violated
* invariants are violated
*/ */
public static CallSite altMetaFactory(MethodHandles.Lookup caller, public static CallSite altMetaFactory(MethodHandles.Lookup caller,
String invokedName, String invokedName,
...@@ -267,7 +239,6 @@ public class LambdaMetafactory { ...@@ -267,7 +239,6 @@ public class LambdaMetafactory {
MethodType instantiatedMethodType = (MethodType)args[2]; MethodType instantiatedMethodType = (MethodType)args[2];
int flags = (Integer) args[3]; int flags = (Integer) args[3];
Class<?>[] markerInterfaces; Class<?>[] markerInterfaces;
MethodType[] bridges;
int argIndex = 4; int argIndex = 4;
if ((flags & FLAG_MARKERS) != 0) { if ((flags & FLAG_MARKERS) != 0) {
int markerCount = (Integer) args[argIndex++]; int markerCount = (Integer) args[argIndex++];
...@@ -277,30 +248,9 @@ public class LambdaMetafactory { ...@@ -277,30 +248,9 @@ public class LambdaMetafactory {
} }
else else
markerInterfaces = EMPTY_CLASS_ARRAY; markerInterfaces = EMPTY_CLASS_ARRAY;
if ((flags & FLAG_BRIDGES) != 0) { AbstractValidatingLambdaMetafactory mf;
int bridgeCount = (Integer) args[argIndex++]; mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod, implMethod, instantiatedMethodType,
bridges = new MethodType[bridgeCount]; flags, markerInterfaces);
System.arraycopy(args, argIndex, bridges, 0, bridgeCount);
argIndex += bridgeCount;
}
else
bridges = EMPTY_MT_ARRAY;
boolean foundSerializableSupertype = Serializable.class.isAssignableFrom(invokedType.returnType());
for (Class<?> c : markerInterfaces)
foundSerializableSupertype |= Serializable.class.isAssignableFrom(c);
boolean isSerializable = ((flags & LambdaMetafactory.FLAG_SERIALIZABLE) != 0)
|| foundSerializableSupertype;
if (isSerializable && !foundSerializableSupertype) {
markerInterfaces = Arrays.copyOf(markerInterfaces, markerInterfaces.length + 1);
markerInterfaces[markerInterfaces.length-1] = Serializable.class;
}
AbstractValidatingLambdaMetafactory mf
= new InnerClassLambdaMetafactory(caller, invokedType, samMethod,
implMethod, instantiatedMethodType,
isSerializable, markerInterfaces, bridges);
mf.validateMetafactoryArgs(); mf.validateMetafactoryArgs();
return mf.buildCallSite(); return mf.buildCallSite();
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
新手
引导
客服 返回
顶部