--- a/jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java Fri Feb 15 11:06:52 2013 +0000
+++ b/jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java Sat Feb 16 12:36:54 2013 -0800
@@ -34,11 +34,11 @@
import static sun.invoke.util.Wrapper.*;
/**
- * Abstract implementation of a meta-factory which provides parameter unrolling and input validation.
+ * Abstract implementation of a lambda metafactory which provides parameter unrolling and input validation.
*
- * @author Robert Field
+ * @see LambdaMetafactory
*/
-/*non-public*/ abstract class AbstractValidatingLambdaMetafactory {
+/* package */ abstract class AbstractValidatingLambdaMetafactory {
/*
* For context, the comments for the following fields are marked in quotes with their values, given this program:
@@ -54,16 +54,19 @@
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 MethodHandle samMethod; // Raw method handle for the functional interface method
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 MethodHandle implMethod; // Raw method handle for the implementation method
final MethodHandleInfo implInfo; // Info about the implementation method handle "MethodHandleInfo[5 CC.impl(int)String]"
final int implKind; // Invocation kind for implementation "5"=invokevirtual
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 instantiatedMethodType; // Instantiated erased functional interface method type "(Integer)Object"
+ final boolean isSerializable; // Should the returned instance be serializable
+ final Class<?>[] markerInterfaces; // Additional marker interfaces to be implemented
/**
@@ -80,27 +83,35 @@
* @param implMethod The implementation method which should be called (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 SAM method from the functional interface's perspective
+ * @param instantiatedMethodType The signature of the primary functional interface method after type variables
+ * are substituted with their instantiation from the capture site
* @throws ReflectiveOperationException
+ * @throws LambdaConversionException If any of the meta-factory protocol invariants are violated
*/
AbstractValidatingLambdaMetafactory(MethodHandles.Lookup caller,
MethodType invokedType,
MethodHandle samMethod,
MethodHandle implMethod,
- MethodType instantiatedMethodType)
- throws ReflectiveOperationException {
+ MethodType instantiatedMethodType,
+ int flags,
+ Class<?>[] markerInterfaces)
+ throws ReflectiveOperationException, LambdaConversionException {
this.targetClass = caller.lookupClass();
this.invokedType = invokedType;
this.samBase = invokedType.returnType();
- this.isSerializable = Serializable.class.isAssignableFrom(samBase);
+ this.samMethod = samMethod;
this.samInfo = new MethodHandleInfo(samMethod);
this.samClass = samInfo.getDeclaringClass();
this.samMethodType = samInfo.getMethodType();
+ this.implMethod = implMethod;
this.implInfo = new MethodHandleInfo(implMethod);
- this.implKind = implInfo.getReferenceKind() == MethodHandleInfo.REF_invokeSpecial? MethodHandleInfo.REF_invokeVirtual : implInfo.getReferenceKind(); // @@@ Temp work-around to hotspot incorrectly converting to invokespecial
+ // @@@ Temporary work-around pending resolution of 8005119
+ this.implKind = (implInfo.getReferenceKind() == MethodHandleInfo.REF_invokeSpecial)
+ ? MethodHandleInfo.REF_invokeVirtual
+ : implInfo.getReferenceKind();
this.implIsInstanceMethod =
implKind == MethodHandleInfo.REF_invokeVirtual ||
implKind == MethodHandleInfo.REF_invokeSpecial ||
@@ -109,6 +120,30 @@
this.implMethodType = implInfo.getMethodType();
this.instantiatedMethodType = instantiatedMethodType;
+
+ if (!samClass.isInterface()) {
+ throw new LambdaConversionException(String.format(
+ "Functional interface %s is not an interface",
+ samClass.getName()));
+ }
+
+ boolean foundSerializableSupertype = Serializable.class.isAssignableFrom(samBase);
+ for (Class<?> c : markerInterfaces) {
+ if (!c.isInterface()) {
+ throw new LambdaConversionException(String.format(
+ "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;
}
/**
@@ -127,8 +162,9 @@
void validateMetafactoryArgs() throws LambdaConversionException {
// Check target type is a subtype of class where SAM method is defined
if (!samClass.isAssignableFrom(samBase)) {
- throw new LambdaConversionException(String.format("Invalid target type %s for lambda conversion; not a subtype of functional interface %s",
- samBase.getName(), samClass.getName()));
+ throw new LambdaConversionException(
+ String.format("Invalid target type %s for lambda conversion; not a subtype of functional interface %s",
+ samBase.getName(), samClass.getName()));
}
switch (implKind) {
@@ -149,14 +185,16 @@
final int samArity = samMethodType.parameterCount();
final int instantiatedArity = instantiatedMethodType.parameterCount();
if (implArity + receiverArity != capturedArity + samArity) {
- 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));
+ throw new LambdaConversionException(
+ String.format("Incorrect number of parameters for %s method %s; %d captured parameters, %d functional interface method parameters, %d implementation parameters",
+ implIsInstanceMethod ? "instance" : "static", implInfo,
+ capturedArity, samArity, implArity));
}
if (instantiatedArity != samArity) {
- throw new LambdaConversionException(String.format("Incorrect number of parameters for %s method %s; %d functional interface parameters, %d SAM method parameters",
- implIsInstanceMethod ? "instance" : "static", implInfo,
- instantiatedArity, samArity));
+ throw new LambdaConversionException(
+ String.format("Incorrect number of parameters for %s method %s; %d instantiated parameters, %d functional interface method parameters",
+ implIsInstanceMethod ? "instance" : "static", implInfo,
+ instantiatedArity, samArity));
}
// If instance: first captured arg (receiver) must be subtype of class where impl method is defined
@@ -180,8 +218,9 @@
// check receiver type
if (!implDefiningClass.isAssignableFrom(receiverClass)) {
- throw new LambdaConversionException(String.format("Invalid receiver type %s; not a subtype of implementation type %s",
- receiverClass, implDefiningClass));
+ throw new LambdaConversionException(
+ String.format("Invalid receiver type %s; not a subtype of implementation type %s",
+ receiverClass, implDefiningClass));
}
} else {
// no receiver
@@ -196,7 +235,8 @@
Class<?> capturedParamType = invokedType.parameterType(i + capturedStart);
if (!capturedParamType.equals(implParamType)) {
throw new LambdaConversionException(
- String.format("Type mismatch in captured lambda parameter %d: expecting %s, found %s", i, capturedParamType, implParamType));
+ String.format("Type mismatch in captured lambda parameter %d: expecting %s, found %s",
+ i, capturedParamType, implParamType));
}
}
// Check for adaptation match on SAM arguments
@@ -206,7 +246,8 @@
Class<?> instantiatedParamType = instantiatedMethodType.parameterType(i + samOffset);
if (!isAdaptableTo(instantiatedParamType, implParamType, true)) {
throw new LambdaConversionException(
- String.format("Type mismatch for lambda argument %d: %s is not convertible to %s", i, instantiatedParamType, implParamType));
+ String.format("Type mismatch for lambda argument %d: %s is not convertible to %s",
+ i, instantiatedParamType, implParamType));
}
}
@@ -218,7 +259,8 @@
: implMethodType.returnType();
if (!isAdaptableToAsReturn(actualReturnType, expectedType)) {
throw new LambdaConversionException(
- String.format("Type mismatch for lambda return: %s is not convertible to %s", actualReturnType, expectedType));
+ String.format("Type mismatch for lambda return: %s is not convertible to %s",
+ actualReturnType, expectedType));
}
}
@@ -274,8 +316,8 @@
}
- /*********** Logging support -- for debugging only
- static final Executor logPool = Executors.newSingleThreadExecutor(); // @@@ For debugging only
+ /*********** Logging support -- for debugging only, uncomment as needed
+ static final Executor logPool = Executors.newSingleThreadExecutor();
protected static void log(final String s) {
MethodHandleProxyLambdaMetafactory.logPool.execute(new Runnable() {
@Override
@@ -297,17 +339,21 @@
***********************/
/**
- * Find the SAM method and corresponding methods which should be bridged. SAM method and those to be bridged
- * will have the same name and number of parameters. Check for matching default methods (non-abstract), they
- * should not be bridged-over and indicate a complex bridging situation.
+ * 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 final List<Method> methodsFound = new ArrayList<>(methods.length);
private Method samMethod = null;
private final List<Method> methodsToBridge = new ArrayList<>(methods.length);
- private boolean defaultMethodFound = false;
+ private boolean conflictFoundBetweenDefaultAndBridge = false;
MethodAnalyzer() {
String samMethodName = samInfo.getName();
@@ -315,31 +361,36 @@
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())) {
- // Exclude methods with duplicate signatures
- if (methodUnique(m)) {
- if (m.getReturnType().equals(samReturnType) && Arrays.equals(mParamTypes, samParamTypes)) {
- // Exact match, this is the SAM method signature
- samMethod = m;
- } else {
- methodsToBridge.add(m);
- }
+ // 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 {
- // This is a default method, flag for special processing
- defaultMethodFound = true;
- // Ignore future matching abstracts.
- // Note, due to reabstraction, this is really a punt, hence pass-off to VM
- methodUnique(m);
+ // Record default methods for conflict testing
+ defaultMethods.add(m);
}
}
}
}
+ for (Method dm : defaultMethods) {
+ if (hasMatchingBridgeSignature(dm)) {
+ conflictFoundBetweenDefaultAndBridge = true;
+ break;
+ }
+ }
}
Method getSamMethod() {
@@ -350,27 +401,26 @@
return methodsToBridge;
}
- boolean wasDefaultMethodFound() {
- return defaultMethodFound;
+ boolean conflictFoundBetweenDefaultAndBridge() {
+ return conflictFoundBetweenDefaultAndBridge;
}
/**
- * Search the list of previously found methods to determine if there is a method with the same signature
- * (return and parameter types) as the specified method. If it wasn't found before, add to the found list.
+ * 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 False if the method was found, True otherwise
+ * @return True if the method was found, False otherwise
*/
- private boolean methodUnique(Method m) {
+ private boolean hasMatchingBridgeSignature(Method m) {
Class<?>[] ptypes = m.getParameterTypes();
Class<?> rtype = m.getReturnType();
- for (Method md : methodsFound) {
+ for (Method md : methodsToBridge) {
if (md.getReturnType().equals(rtype) && Arrays.equals(ptypes, md.getParameterTypes())) {
+ return true;
+ }
+ }
return false;
}
}
- methodsFound.add(m);
- return true;
- }
- }
}
--- a/jdk/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java Fri Feb 15 11:06:52 2013 +0000
+++ b/jdk/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java Sat Feb 16 12:36:54 2013 -0800
@@ -36,21 +36,28 @@
import java.security.PrivilegedAction;
/**
- * InnerClassLambdaMetafactory
+ * Lambda metafactory implementation which dynamically creates an inner-class-like class per lambda callsite.
+ *
+ * @see LambdaMetafactory
*/
-/*non-public*/ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
+/* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
private static final int CLASSFILE_VERSION = 51;
- private static final Type TYPE_VOID = Type.getType(void.class);
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_SERIALIZABLE = "java/io/Serializable";
private static final String NAME_CTOR = "<init>";
//Serialization support
- private static final String NAME_SERIALIZED_LAMBDA = "com/oracle/java/lang/invoke/SerializedLambdaImpl";
+ private static final String NAME_SERIALIZED_LAMBDA = "java/lang/invoke/SerializedLambda";
private static final String DESCR_METHOD_WRITE_REPLACE = "()Ljava/lang/Object;";
private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace";
private static final String NAME_OBJECT = "java/lang/Object";
+ private static final String DESCR_CTOR_SERIALIZED_LAMBDA
+ = MethodType.methodType(void.class,
+ String.class,
+ int.class, String.class, String.class, String.class,
+ int.class, String.class, String.class, String.class,
+ String.class,
+ Object[].class).toMethodDescriptorString();
// Used to ensure that each spun class name is unique
private static final AtomicInteger counter = new AtomicInteger(0);
@@ -70,7 +77,7 @@
private final Type[] instantiatedArgumentTypes; // ASM types for the functional interface arguments
/**
- * Meta-factory constructor.
+ * General meta-factory constructor, standard cases and allowing for uncommon options such as serialization.
*
* @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges
* of the caller.
@@ -83,16 +90,23 @@
* @param implMethod The implementation method which should be called (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 SAM method from the functional interface's perspective
+ * @param instantiatedMethodType The signature of the primary functional interface method after type variables
+ * are substituted with their instantiation from the capture site
+ * @param flags A bitmask containing flags that may influence the translation of this lambda expression. Defined
+ * fields include FLAG_SERIALIZABLE.
+ * @param markerInterfaces Additional interfaces which the lambda object should implement.
* @throws ReflectiveOperationException
+ * @throws LambdaConversionException If any of the meta-factory protocol invariants are violated
*/
public InnerClassLambdaMetafactory(MethodHandles.Lookup caller,
MethodType invokedType,
MethodHandle samMethod,
MethodHandle implMethod,
- MethodType instantiatedMethodType)
- throws ReflectiveOperationException {
- super(caller, invokedType, samMethod, implMethod, instantiatedMethodType);
+ MethodType instantiatedMethodType,
+ int flags,
+ Class<?>[] markerInterfaces)
+ throws ReflectiveOperationException, LambdaConversionException {
+ super(caller, invokedType, samMethod, implMethod, instantiatedMethodType, flags, markerInterfaces);
implMethodClassName = implDefiningClass.getName().replace('.', '/');
implMethodName = implInfo.getName();
implMethodDesc = implMethodType.toMethodDescriptorString();
@@ -109,7 +123,6 @@
argNames[i] = "arg$" + (i + 1);
}
instantiatedArgumentTypes = Type.getArgumentTypes(instantiatedMethodType.toMethodDescriptorString());
-
}
/**
@@ -120,7 +133,8 @@
*
* @return a CallSite, which, when invoked, will return an instance of the
* functional interface
- * @throws ReflectiveOperationException, LambdaConversionException
+ * @throws ReflectiveOperationException
+ * @throws LambdaConversionException If properly formed functional interface is not found
*/
@Override
CallSite buildCallSite() throws ReflectiveOperationException, LambdaConversionException {
@@ -151,8 +165,8 @@
} else {
return new ConstantCallSite(
MethodHandles.Lookup.IMPL_LOOKUP
- .findConstructor(innerClass, constructorType)
- .asType(constructorType.changeReturnType(samBase)));
+ .findConstructor(innerClass, constructorType)
+ .asType(constructorType.changeReturnType(samBase)));
}
}
@@ -161,16 +175,23 @@
* interface, define and return the class.
*
* @return a Class which implements the functional interface
+ * @throws LambdaConversionException If properly formed functional interface is not found
*/
- private <T> Class<? extends T> spinInnerClass() throws LambdaConversionException {
+ private Class<?> spinInnerClass() throws LambdaConversionException {
String samName = samBase.getName().replace('.', '/');
-
- cw.visit(CLASSFILE_VERSION, ACC_SUPER, lambdaClassName, null, NAME_MAGIC_ACCESSOR_IMPL,
- isSerializable ? new String[]{samName, NAME_SERIALIZABLE} : new String[]{samName});
+ String[] interfaces = new String[markerInterfaces.length + 1];
+ interfaces[0] = samName;
+ for (int i=0; i<markerInterfaces.length; i++) {
+ interfaces[i+1] = markerInterfaces[i].getName().replace('.', '/');
+ }
+ cw.visit(CLASSFILE_VERSION, ACC_SUPER,
+ lambdaClassName, null,
+ NAME_MAGIC_ACCESSOR_IMPL, interfaces);
// 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);
+ FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL, argNames[i], argTypes[i].getDescriptor(),
+ null, null);
fv.visitEnd();
}
@@ -180,26 +201,24 @@
// Forward the SAM method
if (ma.getSamMethod() == null) {
- throw new LambdaConversionException(String.format("SAM method not found: %s", samMethodType));
+ throw new LambdaConversionException(String.format("Functional interface method not found: %s", samMethodType));
} else {
generateForwardingMethod(ma.getSamMethod(), false);
}
// Forward the bridges
- // @@@ Once the VM can do fail-over, uncomment the default method test
- if (!ma.getMethodsToBridge().isEmpty() /* && !ma.wasDefaultMethodFound() */) {
+ // @@@ The commented-out code is temporary, pending the VM's ability to bridge all methods on request
+ // @@@ Once the VM can do fail-over, uncomment the !ma.wasDefaultMethodFound() test, and emit the appropriate
+ // @@@ classfile attribute to request custom bridging. See 8002092.
+ if (!ma.getMethodsToBridge().isEmpty() /* && !ma.conflictFoundBetweenDefaultAndBridge() */ ) {
for (Method m : ma.getMethodsToBridge()) {
generateForwardingMethod(m, true);
}
}
- /***** Serialization not yet supported
if (isSerializable) {
- String samMethodName = samInfo.getName();
- Type samType = Type.getType(samBase);
- generateSerializationMethod(samType, samMethodName);
+ generateWriteReplace();
}
- ******/
cw.visitEnd();
@@ -212,7 +231,7 @@
try (FileOutputStream fos = new FileOutputStream(lambdaClassName.replace('/', '.') + ".class")) {
fos.write(classBytes);
} catch (IOException ex) {
- Logger.getLogger(InnerClassLambdaMetafactory.class.getName()).log(Level.SEVERE, null, ex);
+ PlatformLogger.getLogger(InnerClassLambdaMetafactory.class.getName()).severe(ex.getMessage(), ex);
}
***/
@@ -228,7 +247,8 @@
}
);
- return (Class<? extends T>) Unsafe.getUnsafe().defineClass(lambdaClassName, classBytes, 0, classBytes.length, loader, pd);
+ return (Class<?>) Unsafe.getUnsafe().defineClass(lambdaClassName, classBytes, 0, classBytes.length,
+ loader, pd);
}
/**
@@ -253,40 +273,44 @@
}
/**
- * Generate the serialization method (if needed)
+ * Generate the writeReplace method (if needed for serialization)
*/
- /****** This code is out of date -- known to be wrong -- and not currently used ******
- private void generateSerializationMethod(Type samType, String samMethodName) {
- String samMethodDesc = samMethodType.toMethodDescriptorString();
- TypeConvertingMethodAdapter mv = new TypeConvertingMethodAdapter(cw.visitMethod(ACC_PRIVATE + ACC_FINAL, NAME_METHOD_WRITE_REPLACE, DESCR_METHOD_WRITE_REPLACE, null, null));
+ private void generateWriteReplace() {
+ TypeConvertingMethodAdapter mv
+ = new TypeConvertingMethodAdapter(cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
+ NAME_METHOD_WRITE_REPLACE, DESCR_METHOD_WRITE_REPLACE,
+ null, null));
mv.visitCode();
mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA);
- mv.dup();
- mv.visitLdcInsn(samType);
- mv.visitLdcInsn(samMethodName);
- mv.visitLdcInsn(samMethodDesc);
- mv.visitLdcInsn(Type.getType(implDefiningClass));
- mv.visitLdcInsn(implMethodName);
- mv.visitLdcInsn(implMethodDesc);
+ mv.visitInsn(DUP);;
+ mv.visitLdcInsn(targetClass.getName().replace('.', '/'));
+ mv.visitLdcInsn(samInfo.getReferenceKind());
+ mv.visitLdcInsn(invokedType.returnType().getName().replace('.', '/'));
+ mv.visitLdcInsn(samInfo.getName());
+ mv.visitLdcInsn(samInfo.getMethodType().toMethodDescriptorString());
+ mv.visitLdcInsn(implInfo.getReferenceKind());
+ mv.visitLdcInsn(implInfo.getDeclaringClass().getName().replace('.', '/'));
+ mv.visitLdcInsn(implInfo.getName());
+ mv.visitLdcInsn(implInfo.getMethodType().toMethodDescriptorString());
+ mv.visitLdcInsn(instantiatedMethodType.toMethodDescriptorString());
mv.iconst(argTypes.length);
mv.visitTypeInsn(ANEWARRAY, NAME_OBJECT);
for (int i = 0; i < argTypes.length; i++) {
- mv.dup();
+ mv.visitInsn(DUP);
mv.iconst(i);
mv.visitVarInsn(ALOAD, 0);
- mv.getfield(lambdaClassName, argNames[i], argTypes[i].getDescriptor());
- mv.boxIfPrimitive(argTypes[i]);
+ mv.visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor());
+ mv.boxIfTypePrimitive(argTypes[i]);
mv.visitInsn(AASTORE);
}
- mv.invokespecial(NAME_SERIALIZED_LAMBDA, NAME_CTOR,
- "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V");
+ mv.visitMethodInsn(INVOKESPECIAL, NAME_SERIALIZED_LAMBDA, NAME_CTOR,
+ DESCR_CTOR_SERIALIZED_LAMBDA);
mv.visitInsn(ARETURN);
mv.visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
mv.visitEnd();
}
- ********/
/**
* Generate a method which calls the lambda implementation method,
@@ -321,11 +345,11 @@
if (implKind == MethodHandleInfo.REF_newInvokeSpecial) {
visitTypeInsn(NEW, implMethodClassName);
- dup();
+ visitInsn(DUP);;
}
for (int i = 0; i < argTypes.length; i++) {
visitVarInsn(ALOAD, 0);
- getfield(lambdaClassName, argNames[i], argTypes[i].getDescriptor());
+ visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor());
}
convertArgumentTypes(Type.getArgumentTypes(m));
@@ -337,7 +361,7 @@
// Note: if adapting from non-void to void, the 'return' instruction will pop the unneeded result
Type samReturnType = Type.getReturnType(m);
convertType(implMethodReturnType, samReturnType, samReturnType);
- areturn(samReturnType);
+ visitInsn(samReturnType.getOpcode(Opcodes.IRETURN));
visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
visitEnd();
@@ -352,7 +376,7 @@
Type rcvrType = samArgumentTypes[0];
Type instantiatedRcvrType = instantiatedArgumentTypes[0];
- load(lvIndex + 1, rcvrType);
+ visitVarInsn(rcvrType.getOpcode(ILOAD), lvIndex + 1);
lvIndex += rcvrType.getSize();
convertType(rcvrType, Type.getType(implDefiningClass), instantiatedRcvrType);
}
@@ -362,7 +386,7 @@
Type targetType = implMethodArgumentTypes[argOffset + i];
Type instantiatedArgType = instantiatedArgumentTypes[i];
- load(lvIndex + 1, argType);
+ visitVarInsn(argType.getOpcode(ILOAD), lvIndex + 1);
lvIndex += argType.getSize();
convertType(argType, targetType, instantiatedArgType);
}
@@ -388,45 +412,5 @@
throw new InternalError("Unexpected invocation kind: " + implKind);
}
}
-
- /**
- * The following methods are copied from
- * org.objectweb.asm.commons.InstructionAdapter. Part of ASM: a very
- * small and fast Java bytecode manipulation framework. Copyright (c)
- * 2000-2005 INRIA, France Telecom All rights reserved.
- *
- * Subclass with that (removing these methods) if that package/class is
- * ever added to the JDK.
- */
- private void iconst(final int cst) {
- if (cst >= -1 && cst <= 5) {
- mv.visitInsn(Opcodes.ICONST_0 + cst);
- } else if (cst >= Byte.MIN_VALUE && cst <= Byte.MAX_VALUE) {
- mv.visitIntInsn(Opcodes.BIPUSH, cst);
- } else if (cst >= Short.MIN_VALUE && cst <= Short.MAX_VALUE) {
- mv.visitIntInsn(Opcodes.SIPUSH, cst);
- } else {
- mv.visitLdcInsn(cst);
- }
- }
-
- private void load(final int var, final Type type) {
- mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), var);
- }
-
- private void dup() {
- mv.visitInsn(Opcodes.DUP);
- }
-
- private void areturn(final Type t) {
- mv.visitInsn(t.getOpcode(Opcodes.IRETURN));
- }
-
- private void getfield(
- final String owner,
- final String name,
- final String desc) {
- mv.visitFieldInsn(Opcodes.GETFIELD, owner, name, desc);
- }
}
}
--- a/jdk/src/share/classes/java/lang/invoke/LambdaMetafactory.java Fri Feb 15 11:06:52 2013 +0000
+++ b/jdk/src/share/classes/java/lang/invoke/LambdaMetafactory.java Sat Feb 16 12:36:54 2013 -0800
@@ -42,14 +42,13 @@
* method, and the static types of the captured lambda arguments, and link a call site which, when invoked,
* produces the lambda object.
*
- * <p>Two pieces of information are needed about the functional interface: the SAM method and the type of the SAM
- * method in the functional interface. The type can be different when parameterized types are used. For example,
- * consider
- * <code>interface I<T> { int m(T x); }</code> if this SAM type is used in a lambda
- * <code>I<Byte> v = ...</code>, we need both the actual SAM method which has the signature
- * <code>(Object)int</code> and the functional interface type of the method, which has signature
- * <code>(Byte)int</code>. The latter is the instantiated erased functional interface method type, or
- * simply <I>instantiated method type</I>.
+ * <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
+ * <code>interface I<T> { int m(T x); }</code> if this functional interface type is used in a lambda
+ * <code>I<Byte> v = ...</code>, we need both the actual functional interface method which has the signature
+ * <code>(Object)int</code> and the erased instantiated type of the functional interface method (or simply
+ * <I>instantiated method type</I>), which has signature
+ * <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
@@ -138,11 +137,25 @@
* </tr>
* </table>
*
+ * The default bootstrap ({@link #metaFactory}) represents the common cases and uses an optimized protocol.
+ * Alternate bootstraps (e.g., {@link #altMetaFactory}) exist to support uncommon cases such as serialization
+ * or additional marker superinterfaces.
*
*/
public class LambdaMetafactory {
+ /** Flag for alternate metafactories indicating the lambda object is must to be serializable */
+ public static final int FLAG_SERIALIZABLE = 1 << 0;
+
/**
+ * Flag for alternate metafactories indicating the lambda object implements other marker interfaces
+ * besides Serializable
+ */
+ public static final int FLAG_MARKERS = 1 << 1;
+
+ private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
+
+/**
* Standard meta-factory for conversion of lambda expressions or method references to functional interfaces.
*
* @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges
@@ -158,7 +171,8 @@
* @param implMethod The implementation method which should be called (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 SAM method from the functional interface's perspective
+ * @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 LambdaConversionException If any of the meta-factory protocol invariants are violated
@@ -171,7 +185,85 @@
MethodType instantiatedMethodType)
throws ReflectiveOperationException, LambdaConversionException {
AbstractValidatingLambdaMetafactory mf;
- mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod, implMethod, instantiatedMethodType);
+ mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod, implMethod, instantiatedMethodType,
+ 0, EMPTY_CLASS_ARRAY);
+ mf.validateMetafactoryArgs();
+ return mf.buildCallSite();
+ }
+
+ /**
+ * Alternate meta-factory for conversion of lambda expressions or method references to functional interfaces,
+ * which supports serialization and other uncommon options.
+ *
+ * The declared argument list for this method is:
+ *
+ * CallSite altMetaFactory(MethodHandles.Lookup caller,
+ * String invokedName,
+ * MethodType invokedType,
+ * Object... args)
+ *
+ * but it behaves as if the argument list is:
+ *
+ * CallSite altMetaFactory(MethodHandles.Lookup caller,
+ * String invokedName,
+ * MethodType invokedType,
+ * MethodHandle samMethod
+ * MethodHandle implMethod,
+ * MethodType instantiatedMethodType,
+ * int flags,
+ * int markerInterfaceCount, // IF flags has MARKERS set
+ * Class... markerInterfaces // IF flags has MARKERS set
+ * )
+ *
+ *
+ * @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges
+ * of the caller.
+ * @param invokedName Stacked automatically by VM; the name of the invoked method as it appears at the call site.
+ * Currently unused.
+ * @param invokedType Stacked automatically by VM; the signature of the invoked method, which includes the
+ * expected static type of the returned lambda object, and the static types of the captured
+ * arguments for the lambda. In the event that the implementation method is an instance method,
+ * the first argument in the invocation signature will correspond to the receiver.
+ * @param samMethod The primary method in the functional interface to which the lambda or method reference is
+ * being converted, represented as a method handle.
+ * @param implMethod The implementation method which should be called (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 flags A bitmask containing flags that may influence the translation of this lambda expression. Defined
+ * fields include FLAG_SERIALIZABLE and FLAG_MARKERS.
+ * @param markerInterfaceCount If the FLAG_MARKERS flag is set, this is a count of the number of additional
+ * marker interfaces
+ * @param markerInterfaces If the FLAG_MARKERS flag is set, this consists of Class objects identifying additional
+ * marker interfaces which the lambda object should implement, whose count equals
+ * markerInterfaceCount
+ * @return a CallSite, which, when invoked, will return an instance of the functional interface
+ * @throws ReflectiveOperationException
+ * @throws LambdaConversionException If any of the meta-factory protocol invariants are violated
+ */
+ public static CallSite altMetaFactory(MethodHandles.Lookup caller,
+ String invokedName,
+ MethodType invokedType,
+ Object... args)
+ throws ReflectiveOperationException, LambdaConversionException {
+ MethodHandle samMethod = (MethodHandle)args[0];
+ MethodHandle implMethod = (MethodHandle)args[1];
+ MethodType instantiatedMethodType = (MethodType)args[2];
+ int flags = (Integer) args[3];
+ Class<?>[] markerInterfaces;
+ int argIndex = 4;
+ if ((flags & FLAG_MARKERS) != 0) {
+ int markerCount = (Integer) args[argIndex++];
+ markerInterfaces = new Class<?>[markerCount];
+ System.arraycopy(args, argIndex, markerInterfaces, 0, markerCount);
+ argIndex += markerCount;
+ }
+ else
+ markerInterfaces = EMPTY_CLASS_ARRAY;
+ AbstractValidatingLambdaMetafactory mf;
+ mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod, implMethod, instantiatedMethodType,
+ flags, markerInterfaces);
mf.validateMetafactoryArgs();
return mf.buildCallSite();
}
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java Fri Feb 15 11:06:52 2013 +0000
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java Sat Feb 16 12:36:54 2013 -0800
@@ -26,8 +26,11 @@
package java.lang.invoke;
import java.lang.invoke.MethodHandleNatives.Constants;
-//Not yet public: public
-class MethodHandleInfo {
+/**
+ * Cracking (reflecting) method handles back into their constituent symbolic parts.
+ *
+ */
+final class MethodHandleInfo {
public static final int
REF_NONE = Constants.REF_NONE,
REF_getField = Constants.REF_getField,
@@ -65,7 +68,33 @@
return methodType;
}
+ public int getModifiers() {
+ return -1; //TODO
+ }
+
public int getReferenceKind() {
return referenceKind;
}
+
+ static String getReferenceKindString(int referenceKind) {
+ switch (referenceKind) {
+ case REF_NONE: return "REF_NONE";
+ case REF_getField: return "getfield";
+ case REF_getStatic: return "getstatic";
+ case REF_putField: return "putfield";
+ case REF_putStatic: return "putstatic";
+ case REF_invokeVirtual: return "invokevirtual";
+ case REF_invokeStatic: return "invokestatic";
+ case REF_invokeSpecial: return "invokespecial";
+ case REF_newInvokeSpecial: return "newinvokespecial";
+ case REF_invokeInterface: return "invokeinterface";
+ default: return "UNKNOWN_REFENCE_KIND" + "[" + referenceKind + "]";
+ }
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s %s.%s:%s", getReferenceKindString(referenceKind),
+ declaringClass.getName(), name, methodType);
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/lang/invoke/SerializedLambda.java Sat Feb 16 12:36:54 2013 -0800
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.invoke;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Objects;
+
+/**
+ * Serialized form of a lambda expression. The properties of this class represent the information that is present
+ * at the lambda factory site, including the identity of the primary functional interface method, the identity of the
+ * implementation method, and any variables captured from the local environment at the time of lambda capture.
+ *
+ * @see LambdaMetafactory
+ */
+public final class SerializedLambda implements Serializable {
+ private static final long serialVersionUID = 8025925345765570181L;
+ private final String capturingClass;
+ private final String functionalInterfaceClass;
+ private final String functionalInterfaceMethodName;
+ private final String functionalInterfaceMethodSignature;
+ private final int functionalInterfaceMethodKind;
+ private final String implClass;
+ private final String implMethodName;
+ private final String implMethodSignature;
+ private final int implMethodKind;
+ private final String instantiatedMethodType;
+ private final Object[] capturedArgs;
+
+ /**
+ * Create a {@code SerializedLambda} from the low-level information present at the lambda factory site.
+ *
+ * @param capturingClass The class in which the lambda expression appears
+ * @param functionalInterfaceMethodKind Method handle kind (see {@link MethodHandleInfo}) for the
+ * functional interface method handle present at the lambda factory site
+ * @param functionalInterfaceClass Name, in slash-delimited form, for the functional interface class present at the
+ * lambda factory site
+ * @param functionalInterfaceMethodName Name of the primary method for the functional interface present at the
+ * lambda factory site
+ * @param functionalInterfaceMethodSignature Signature of the primary method for the functional interface present
+ * at the lambda factory site
+ * @param implMethodKind Method handle kind for the implementation method
+ * @param implClass Name, in slash-delimited form, for the class holding the implementation method
+ * @param implMethodName Name of the implementation method
+ * @param implMethodSignature Signature of the implementation method
+ * @param instantiatedMethodType The signature of the primary functional interface method after type variables
+ * are substituted with their instantiation from the capture site
+ * @param capturedArgs The dynamic arguments to the lambda factory site, which represent variables captured by
+ * the lambda
+ */
+ public SerializedLambda(String capturingClass,
+ int functionalInterfaceMethodKind,
+ String functionalInterfaceClass,
+ String functionalInterfaceMethodName,
+ String functionalInterfaceMethodSignature,
+ int implMethodKind,
+ String implClass,
+ String implMethodName,
+ String implMethodSignature,
+ String instantiatedMethodType,
+ Object[] capturedArgs) {
+ this.capturingClass = capturingClass;
+ this.functionalInterfaceMethodKind = functionalInterfaceMethodKind;
+ this.functionalInterfaceClass = functionalInterfaceClass;
+ this.functionalInterfaceMethodName = functionalInterfaceMethodName;
+ this.functionalInterfaceMethodSignature = functionalInterfaceMethodSignature;
+ this.implMethodKind = implMethodKind;
+ this.implClass = implClass;
+ this.implMethodName = implMethodName;
+ this.implMethodSignature = implMethodSignature;
+ this.instantiatedMethodType = instantiatedMethodType;
+ this.capturedArgs = Objects.requireNonNull(capturedArgs).clone();
+ }
+
+ /** Get the name of the class that captured this lambda */
+ public String getCapturingClass() {
+ return capturingClass;
+ }
+
+ /** Get the name of the functional interface class to which this lambda has been converted */
+ public String getFunctionalInterfaceClass() {
+ return functionalInterfaceClass;
+ }
+
+ /** Get the name of the primary method for the functional interface to which this lambda has been converted */
+ public String getFunctionalInterfaceMethodName() {
+ return functionalInterfaceMethodName;
+ }
+
+ /** Get the signature of the primary method for the functional interface to which this lambda has been converted */
+ public String getFunctionalInterfaceMethodSignature() {
+ return functionalInterfaceMethodSignature;
+ }
+
+ /** Get the method handle kind (see {@link MethodHandleInfo}) of the primary method for the functional interface
+ * to which this lambda has been converted */
+ public int getFunctionalInterfaceMethodKind() {
+ return functionalInterfaceMethodKind;
+ }
+
+ /** Get the name of the class containing the implementation method */
+ public String getImplClass() {
+ return implClass;
+ }
+
+ /** Get the name of the implementation method */
+ public String getImplMethodName() {
+ return implMethodName;
+ }
+
+ /** Get the signature of the implementation method */
+ public String getImplMethodSignature() {
+ return implMethodSignature;
+ }
+
+ /** Get the method handle kind (see {@link MethodHandleInfo}) of the implementation method */
+ public int getImplMethodKind() {
+ return implMethodKind;
+ }
+
+ /**
+ * Get the signature of the primary functional interface method after type variables are substituted with
+ * their instantiation from the capture site
+ */
+ public final String getInstantiatedMethodType() {
+ return instantiatedMethodType;
+ }
+
+ /** Get the count of dynamic arguments to the lambda capture site */
+ public int getCapturedArgCount() {
+ return capturedArgs.length;
+ }
+
+ /** Get a dynamic argument to the lambda capture site */
+ public Object getCapturedArg(int i) {
+ return capturedArgs[i];
+ }
+
+ private Object readResolve() throws ReflectiveOperationException {
+ try {
+ Method deserialize = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
+ @Override
+ public Method run() throws Exception {
+ Class<?> clazz = Class.forName(capturingClass.replace('/', '.'), true,
+ Thread.currentThread().getContextClassLoader());
+ Method m = clazz.getDeclaredMethod("$deserializeLambda$", SerializedLambda.class);
+ m.setAccessible(true);
+ return m;
+ }
+ });
+
+ return deserialize.invoke(null, this);
+ }
+ catch (PrivilegedActionException e) {
+ Exception cause = e.getException();
+ if (cause instanceof ReflectiveOperationException)
+ throw (ReflectiveOperationException) cause;
+ else if (cause instanceof RuntimeException)
+ throw (RuntimeException) cause;
+ else
+ throw new RuntimeException("Exception in SerializedLambda.readResolve", e);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return String.format("SerializedLambda[capturingClass=%s, functionalInterfaceMethod=%s %s.%s:%s, " +
+ "implementation=%s %s.%s:%s, instantiatedMethodType=%s, numCaptured=%d]",
+ capturingClass, MethodHandleInfo.getReferenceKindString(functionalInterfaceMethodKind),
+ functionalInterfaceClass, functionalInterfaceMethodName, functionalInterfaceMethodSignature,
+ MethodHandleInfo.getReferenceKindString(implMethodKind), implClass, implMethodName,
+ implMethodSignature, instantiatedMethodType, capturedArgs.length);
+ }
+
+ /*
+ // @@@ Review question: is it worthwhile implementing a versioned serialization protocol?
+
+ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
+ }
+
+ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
+ }
+*/
+}
--- a/jdk/src/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java Fri Feb 15 11:06:52 2013 +0000
+++ b/jdk/src/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java Sat Feb 16 12:36:54 2013 -0800
@@ -27,6 +27,7 @@
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.internal.org.objectweb.asm.Type;
import sun.invoke.util.Wrapper;
import static sun.invoke.util.Wrapper.*;
@@ -49,6 +50,9 @@
private static final Wrapper[] FROM_WRAPPER_NAME = new Wrapper[16];
+ // Table of wrappers for primitives, indexed by ASM type sorts
+ private static final Wrapper[] FROM_TYPE_SORT = new Wrapper[16];
+
static {
for (Wrapper w : Wrapper.values()) {
if (w.basicTypeChar() != 'L') {
@@ -71,6 +75,15 @@
initWidening(DOUBLE, Opcodes.I2D, BYTE, SHORT, INT, CHAR);
initWidening(DOUBLE, Opcodes.F2D, FLOAT);
initWidening(DOUBLE, Opcodes.L2D, LONG);
+
+ FROM_TYPE_SORT[Type.BYTE] = Wrapper.BYTE;
+ FROM_TYPE_SORT[Type.SHORT] = Wrapper.SHORT;
+ FROM_TYPE_SORT[Type.INT] = Wrapper.INT;
+ FROM_TYPE_SORT[Type.LONG] = Wrapper.LONG;
+ FROM_TYPE_SORT[Type.CHAR] = Wrapper.CHAR;
+ FROM_TYPE_SORT[Type.FLOAT] = Wrapper.FLOAT;
+ FROM_TYPE_SORT[Type.DOUBLE] = Wrapper.DOUBLE;
+ FROM_TYPE_SORT[Type.BOOLEAN] = Wrapper.BOOLEAN;
}
private static void initWidening(Wrapper to, int opcode, Wrapper... from) {
@@ -124,8 +137,9 @@
return "()" + w.basicTypeChar();
}
- void boxIfPrimitive(Wrapper w) {
- if (w.zero() != null) {
+ void boxIfTypePrimitive(Type t) {
+ Wrapper w = FROM_TYPE_SORT[t.getSort()];
+ if (w != null) {
box(w);
}
}
@@ -264,4 +278,22 @@
}
}
}
+
+ /**
+ * The following method is copied from
+ * org.objectweb.asm.commons.InstructionAdapter. Part of ASM: a very small
+ * and fast Java bytecode manipulation framework.
+ * Copyright (c) 2000-2005 INRIA, France Telecom All rights reserved.
+ */
+ void iconst(final int cst) {
+ if (cst >= -1 && cst <= 5) {
+ mv.visitInsn(Opcodes.ICONST_0 + cst);
+ } else if (cst >= Byte.MIN_VALUE && cst <= Byte.MAX_VALUE) {
+ mv.visitIntInsn(Opcodes.BIPUSH, cst);
+ } else if (cst >= Short.MIN_VALUE && cst <= Short.MAX_VALUE) {
+ mv.visitIntInsn(Opcodes.SIPUSH, cst);
+ } else {
+ mv.visitLdcInsn(cst);
+ }
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/lambda/LambdaSerialization.java Sat Feb 16 12:36:54 2013 -0800
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+@test
+@bug 8004970
+@summary Lambda serialization
+
+*/
+
+import java.io.*;
+
+public class LambdaSerialization {
+
+ static int assertionCount = 0;
+
+ static void assertTrue(boolean cond) {
+ assertionCount++;
+ if (!cond)
+ throw new AssertionError();
+ }
+
+ public static void main(String[] args) throws Exception {
+ try {
+ // Write lambdas out
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutput out = new ObjectOutputStream(baos);
+
+ write(out, z -> "[" + z + "]" );
+ write(out, z -> z + z );
+ write(out, z -> "blah" );
+ out.flush();
+ out.close();
+
+ // Read them back
+ ByteArrayInputStream bais =
+ new ByteArrayInputStream(baos.toByteArray());
+ ObjectInputStream in = new ObjectInputStream(bais);
+ readAssert(in, "[X]");
+ readAssert(in, "XX");
+ readAssert(in, "blah");
+ in.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw e;
+ }
+ assertTrue(assertionCount == 3);
+ }
+
+ static void write(ObjectOutput out, LSI lamb) throws IOException {
+ out.writeObject(lamb);
+ }
+
+ static void readAssert(ObjectInputStream in, String expected) throws IOException, ClassNotFoundException {
+ LSI ls = (LSI) in.readObject();
+ String result = ls.convert("X");
+ System.out.printf("Result: %s\n", result);
+ assertTrue(result.equals(expected));
+ }
+}
+
+interface LSI extends Serializable {
+ String convert(String x);
+}