OpenJDK / lambda / lambda / jdk
changeset 5971:ac725d3230ec
Security tightening and documentation
author | Robert Field <Robert.Field@oracle.com> |
---|---|
date | Wed, 05 Sep 2012 08:19:59 -0700 |
parents | 6bd7ae62d2bd |
children | d7f2c76afeda 2e6170973d92 |
files | src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java src/share/classes/java/lang/invoke/LambdaMetafactory.java src/share/classes/java/lang/invoke/MethodHandleInfo.java src/share/classes/java/lang/invoke/MethodHandleProxyLambdaMetafactory.java |
diffstat | 5 files changed, 78 insertions(+), 60 deletions(-) [+] |
line wrap: on
line diff
--- a/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java Tue Sep 04 10:54:35 2012 -0700 +++ b/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java Wed Sep 05 08:19:59 2012 -0700 @@ -32,25 +32,35 @@ import java.util.Set; /** - * Abstract implementation of a meta-factory which provides parameter unrolling - * and input validation. + * Abstract implementation of a meta-factory which provides parameter unrolling and input validation. * * @author Robert Field */ -abstract class AbstractValidatingLambdaMetafactory { +/*non-public*/ abstract class AbstractValidatingLambdaMetafactory { - final Class<?> targetClass; - final MethodType invokedType; - final Class<?> samBase; - final boolean isSerializable; - final MethodHandleInfo samInfo; - final Class<?> samClass; - final MethodType samMethodType; - final MethodHandleInfo implInfo; - final boolean implIsInstanceMethod; - final MethodType implMethodType; - final Class<?> implDefiningClass; - final MethodType functionDescType; + /* + * For context, the comments for the following fields are marked in quotes with their values, given this program: + * interface II<T> { Object foo(T x); } + * interface JJ<R extends Number> extends II<R> { } + * class CC { String impl(int i) { return "impl:"+i; }} + * class X { + * public static void main(String[] args) { + * JJ<Integer> iii = (new CC())::impl; + * System.out.printf(">>> %s\n", iii.foo(44)); + * }} + */ + final Class<?> targetClass; // The class calling the meta-factory via invokedynamic "class X" + final MethodType invokedType; // The type of the invoked method "(CC)II" + final Class<?> samBase; // The type of the returned instance "interface JJ" + final boolean isSerializable; // Should the returned instance be serializable + final MethodHandleInfo samInfo; // Info about the SAM method handle "MethodHandleInfo[9 II.foo(Object)Object]" + final Class<?> samClass; // Interface containing the SAM method "interface II" + final MethodType samMethodType; // Type of the SAM method "(Object)Object" + final MethodHandleInfo implInfo; // Info about the implementation method handle "MethodHandleInfo[5 CC.impl(int)String]" + final boolean implIsInstanceMethod; // Is the implementation an instance method "true" + final Class<?> implDefiningClass; // Type defining the implementation "class CC" + final MethodType implMethodType; // Type of the implementation method "(int)String" + final MethodType functionDescType; // Type of the functional interface "(Integer)Object" /** * Meta-factory constructor. @@ -155,9 +165,9 @@ final int capturedArity = invokedType.parameterCount(); final int samArity = samMethodType.parameterCount(); if (implArity + receiverArity != capturedArity + samArity) { - throw new LambdaConversionException(String.format("Incorrect number of parameters for %s method; %d captured parameters, %d functional interface parameters, %d implementation parameters", - implIsInstanceMethod ? "instance" : "static", - capturedArity, samArity, implArity)); + throw new LambdaConversionException(String.format("Incorrect number of parameters for %s method %s; %d captured parameters, %d functional interface parameters, %d implementation parameters", + implIsInstanceMethod ? "instance" : "static", implInfo, + capturedArity, samArity, implArity)); } // If instance: first captured arg (receiver) must be subtype of class where impl method is defined @@ -223,6 +233,12 @@ } } + /** + * Check type adaptability + * @param fromType + * @param toType + * @return True if 'fromType' can be converted to 'toType' + */ private boolean isAdaptableTo(Class<?> fromType, Class<?> toType) { if (fromType.equals(toType)) { return true; @@ -261,6 +277,12 @@ } } + /** + * Check type adaptability for return types (special handling of void type) + * @param fromType + * @param toType + * @return True if 'fromType' can be converted to 'toType' + */ private boolean isAdaptableToAsReturn(Class<?> fromType, Class<?> toType) { return toType.equals(void.class) || !fromType.equals(void.class) && isAdaptableTo(fromType, toType);
--- a/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java Tue Sep 04 10:54:35 2012 -0700 +++ b/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java Wed Sep 05 08:19:59 2012 -0700 @@ -43,7 +43,7 @@ /** * InnerClassLambdaMetafactory */ -class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory { +/*non-public*/ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory { private static final int CLASSFILE_VERSION = 51; private static final String DESCR_METHOD_WRITE_REPLACE = "()Ljava/lang/Object;"; private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace"; @@ -55,29 +55,26 @@ private static final String NAME_SERIALIZED_LAMBDA = "com/oracle/java/lang/invoke/SerializedLambdaImpl"; private static final String NAME_CTOR = "<init>"; - private static final Unsafe unsafe = Unsafe.getUnsafe(); - // Used to ensure that each spun class name is unique private static final AtomicInteger counter = new AtomicInteger(0); - private final int implKind; - private final String implMethodClassName; - private final String implMethodName; - private final String implMethodDesc; - private final Type[] implMethodArgumentTypes; - private final Type implMethodReturnType; - private final MethodType constructorType; - private final ClassWriter cw; - private final String[] argNames; - private final Type[] argTypes; - private final String lambdaClassName; - private final String constructorDesc; - private final Type[] functionalArgumentTypes; + // See context values in AbstractValidatingLambdaMetafactory + private final int implKind; // Invocation kind for implementation "5"=invokevirtual + private final String implMethodClassName; // Name of type containing implementation "CC" + private final String implMethodName; // Name of implementation method "impl" + private final String implMethodDesc; // Type descriptor for implementation methods "(I)Ljava/lang/String;" + private final Type[] implMethodArgumentTypes; // ASM types for implementaion method parameters + private final Type implMethodReturnType; // ASM type for implementaion method return type "Ljava/lang/String;" + private final MethodType constructorType; // Generated class constructor type "(CC)void" + private final String constructorDesc; // Type descriptor for constructor "(LCC;)V" + private final ClassWriter cw; // ASM class writer + private final Type[] argTypes; // ASM types for the constructor arguments + private final String[] argNames; // Generated names for the constructor arguments + private final String lambdaClassName; // Generated name for the generated class "X$$Lambda$1" + private final Type[] functionalArgumentTypes; // ASM types for the functional interface arguments /** * Meta-factory constructor. - private final String constructorDesc; - private final String functionalMethodD * * @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges * of the caller. @@ -149,9 +146,9 @@ * * @return a Class which implements the functional interface */ - private <T> Class<? extends T> spinInnerClass() { + private <T> Class<? extends T> spinInnerClass() { String samMethodName = samInfo.getName(); - + Method[] methods = samBase.getMethods(); String samName = samBase.getName().replace('.', '/'); Type samType = Type.getType(samBase); @@ -159,7 +156,7 @@ cw.visit(CLASSFILE_VERSION, ACC_PUBLIC + ACC_SUPER, lambdaClassName, null, NAME_MAGIC_ACCESSOR_IMPL, isSerializable ? new String[]{samName, NAME_SERIALIZABLE} : new String[]{samName}); - // Generate fields + // Generate final fields to be filled in by constructor for (int i = 0; i < argTypes.length; i++) { FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL, argNames[i], argTypes[i].getDescriptor(), null, null); fv.visitEnd(); @@ -220,7 +217,6 @@ if (!methodsToBridge.isEmpty() /* && !defaultMethodFound*/) { for (Method m : methodsToBridge) { generateForwardingMethod(m, true); - } } @@ -230,17 +226,10 @@ cw.visitEnd(); - return defineGeneratedClass(cw.toByteArray()); - } + // Define the generated class in this VM. - /** - * Define the generated class in this VM. - * - * @param <T> - * @param classBytes The bytes of the class file - * @return the defined class. - */ - private <T> Class<? extends T> defineGeneratedClass(final byte[] classBytes) { + final byte[] classBytes = cw.toByteArray(); + if (System.getProperty("debug.dump.generated") != null) { System.out.printf("Loaded: %s (%d bytes) %n", lambdaClassName, classBytes.length); try (FileOutputStream fos = new FileOutputStream(lambdaClassName.replace('/', '.') + ".class")) { @@ -249,10 +238,10 @@ Logger.getLogger(InnerClassLambdaMetafactory.class.getName()).log(Level.SEVERE, null, ex); } } - + ClassLoader loader = targetClass.getClassLoader(); - ProtectionDomain pd = (loader == null)? null : targetClass.getProtectionDomain(); - return (Class <? extends T>) unsafe.defineClass(lambdaClassName, classBytes, 0, classBytes.length, loader, pd); + ProtectionDomain pd = (loader == null) ? null : targetClass.getProtectionDomain(); + return (Class<? extends T>) Unsafe.getUnsafe().defineClass(lambdaClassName, classBytes, 0, classBytes.length, loader, pd); } /**
--- a/src/share/classes/java/lang/invoke/LambdaMetafactory.java Tue Sep 04 10:54:35 2012 -0700 +++ b/src/share/classes/java/lang/invoke/LambdaMetafactory.java Wed Sep 05 08:19:59 2012 -0700 @@ -43,14 +43,16 @@ * method, and the static types of the captured lambda arguments, and link a call site which, when invoked, * produces the lambda object. * - * <p>While functional interfaces only have a single non-Object method from the language perspective, 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>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) * may differ in several ways. The implementation methods may have additional arguments to accommodate arguments * captured by the lambda expression; there may also be differences resulting from permitted adaptations of - * arguments, such as casting, boxing, unboxing, and primitive widening. + * arguments, such as casting, boxing, unboxing, and primitive widening. They may also differ because of var-args, + * but this is handled in the compiler by adapter methods for the implementation method. * * <p>Invokedynamic call sites have two argument lists: a static argument list and a dynamic argument list. The * static argument list lives in the constant pool; the dynamic argument list lives on the operand stack at
--- a/src/share/classes/java/lang/invoke/MethodHandleInfo.java Tue Sep 04 10:54:35 2012 -0700 +++ b/src/share/classes/java/lang/invoke/MethodHandleInfo.java Wed Sep 05 08:19:59 2012 -0700 @@ -30,7 +30,7 @@ * Cracking (reflecting) method handles back into their constituent symbolic parts. * */ -public class MethodHandleInfo { +public final class MethodHandleInfo { public static final int REF_NONE = Constants.REF_NONE, REF_getField = Constants.REF_getField, @@ -74,5 +74,10 @@ public int getReferenceKind() { return referenceKind; - } + } + + @Override + public String toString() { + return String.format("MethodHandleInfo[%d %s.%s%s]", referenceKind, declaringClass.getName(), name, methodType); + } }
--- a/src/share/classes/java/lang/invoke/MethodHandleProxyLambdaMetafactory.java Tue Sep 04 10:54:35 2012 -0700 +++ b/src/share/classes/java/lang/invoke/MethodHandleProxyLambdaMetafactory.java Wed Sep 05 08:19:59 2012 -0700 @@ -33,7 +33,7 @@ * * @author Brian Goetz */ -class MethodHandleProxyLambdaMetafactory extends AbstractValidatingLambdaMetafactory { +/*non-public*/ final class MethodHandleProxyLambdaMetafactory extends AbstractValidatingLambdaMetafactory { private final MethodHandle implMethod;