--- a/jdk/src/share/classes/java/lang/Class.java Mon Jun 17 14:23:01 2013 +0100
+++ b/jdk/src/share/classes/java/lang/Class.java Tue Jun 18 09:39:25 2013 +0100
@@ -708,8 +708,9 @@
*/
@SuppressWarnings("unchecked")
public TypeVariable<Class<T>>[] getTypeParameters() {
- if (getGenericSignature() != null)
- return (TypeVariable<Class<T>>[])getGenericInfo().getTypeParameters();
+ ClassRepository info = getGenericInfo();
+ if (info != null)
+ return (TypeVariable<Class<T>>[])info.getTypeParameters();
else
return (TypeVariable<Class<T>>[])new TypeVariable<?>[0];
}
@@ -759,15 +760,19 @@
* @since 1.5
*/
public Type getGenericSuperclass() {
- if (getGenericSignature() != null) {
- // Historical irregularity:
- // Generic signature marks interfaces with superclass = Object
- // but this API returns null for interfaces
- if (isInterface())
- return null;
- return getGenericInfo().getSuperclass();
- } else
+ ClassRepository info = getGenericInfo();
+ if (info == null) {
return getSuperclass();
+ }
+
+ // Historical irregularity:
+ // Generic signature marks interfaces with superclass = Object
+ // but this API returns null for interfaces
+ if (isInterface()) {
+ return null;
+ }
+
+ return info.getSuperclass();
}
/**
@@ -830,7 +835,23 @@
*
* @return an array of interfaces implemented by this class.
*/
- public native Class<?>[] getInterfaces();
+ public Class<?>[] getInterfaces() {
+ ReflectionData<T> rd = reflectionData();
+ if (rd == null) {
+ // no cloning required
+ return getInterfaces0();
+ } else {
+ Class<?>[] interfaces = rd.interfaces;
+ if (interfaces == null) {
+ interfaces = getInterfaces0();
+ rd.interfaces = interfaces;
+ }
+ // defensively copy before handing over to user code
+ return interfaces.clone();
+ }
+ }
+
+ private native Class<?>[] getInterfaces0();
/**
* Returns the {@code Type}s representing the interfaces
@@ -882,10 +903,8 @@
* @since 1.5
*/
public Type[] getGenericInterfaces() {
- if (getGenericSignature() != null)
- return getGenericInfo().getSuperInterfaces();
- else
- return getInterfaces();
+ ClassRepository info = getGenericInfo();
+ return (info == null) ? getInterfaces() : info.getSuperInterfaces();
}
@@ -2396,6 +2415,8 @@
// Intermediate results for getFields and getMethods
volatile Field[] declaredPublicFields;
volatile Method[] declaredPublicMethods;
+ volatile Class<?>[] interfaces;
+
// Value of classRedefinedCount when we created this ReflectionData instance
final int redefinedCount;
@@ -2471,10 +2492,10 @@
}
// Generic signature handling
- private native String getGenericSignature();
+ private native String getGenericSignature0();
// Generic info repository; lazily initialized
- private transient ClassRepository genericInfo;
+ private volatile transient ClassRepository genericInfo;
// accessor for factory
private GenericsFactory getFactory() {
@@ -2482,15 +2503,20 @@
return CoreReflectionFactory.make(this, ClassScope.make(this));
}
- // accessor for generic info repository
+ // accessor for generic info repository;
+ // generic info is lazily initialized
private ClassRepository getGenericInfo() {
- // lazily initialize repository if necessary
+ ClassRepository genericInfo = this.genericInfo;
if (genericInfo == null) {
- // create and cache generic info repository
- genericInfo = ClassRepository.make(getGenericSignature(),
- getFactory());
+ String signature = getGenericSignature0();
+ if (signature == null) {
+ genericInfo = ClassRepository.NONE;
+ } else {
+ genericInfo = ClassRepository.make(signature, getFactory());
+ }
+ this.genericInfo = genericInfo;
}
- return genericInfo; //return cached repository
+ return (genericInfo != ClassRepository.NONE) ? genericInfo : null;
}
// Annotations handling
--- a/jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java Mon Jun 17 14:23:01 2013 +0100
+++ b/jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java Tue Jun 18 09:39:25 2013 +0100
@@ -24,14 +24,11 @@
*/
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 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.
@@ -67,34 +64,52 @@
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
+ final MethodType[] additionalBridges; // Signatures of additional methods to bridge
/**
* Meta-factory constructor.
*
- * @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges
- * of the caller.
- * @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 caller Stacked automatically by VM; represents a lookup context
+ * with the accessibility privileges of the caller.
+ * @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 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 LambdaConversionException If any of the meta-factory protocol invariants are violated
+ * @throws LambdaConversionException If any of the meta-factory protocol
+ * invariants are violated
*/
AbstractValidatingLambdaMetafactory(MethodHandles.Lookup caller,
MethodType invokedType,
MethodHandle samMethod,
MethodHandle implMethod,
MethodType instantiatedMethodType,
- int flags,
- Class<?>[] markerInterfaces)
+ boolean isSerializable,
+ Class<?>[] markerInterfaces,
+ MethodType[] additionalBridges)
throws ReflectiveOperationException, LambdaConversionException {
this.targetClass = caller.lookupClass();
this.invokedType = invokedType;
@@ -118,32 +133,22 @@
implKind == MethodHandleInfo.REF_invokeInterface;
this.implDefiningClass = implInfo.getDeclaringClass();
this.implMethodType = implInfo.getMethodType();
-
this.instantiatedMethodType = instantiatedMethodType;
+ this.isSerializable = isSerializable;
+ this.markerInterfaces = markerInterfaces;
+ this.additionalBridges = additionalBridges;
if (!samClass.isInterface()) {
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) {
if (!c.isInterface()) {
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;
}
/**
@@ -265,9 +270,9 @@
}
/**
- * Check type adaptability
- * @param fromType
- * @param toType
+ * Check type adaptability for parameter types.
+ * @param fromType Type to convert from
+ * @param toType Type to convert to
* @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'
*/
@@ -299,15 +304,14 @@
}
} else {
// both are reference types: fromType should be a superclass of toType.
- return strict? toType.isAssignableFrom(fromType) : true;
+ return !strict || toType.isAssignableFrom(fromType);
}
}
}
/**
- * Check type adaptability for return types -- special handling of void type) and parameterized fromType
- * @param fromType
- * @param toType
+ * Check type adaptability for return types -- special handling of void type)
+ * and parameterized fromType
* @return True if 'fromType' can be converted to 'toType'
*/
private boolean isAdaptableToAsReturn(Class<?> fromType, Class<?> toType) {
@@ -338,89 +342,4 @@
}
***********************/
- /**
- * 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;
- }
- }
}
--- a/jdk/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java Mon Jun 17 14:23:01 2013 +0100
+++ b/jdk/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java Tue Jun 18 09:39:25 2013 +0100
@@ -25,15 +25,16 @@
package java.lang.invoke;
+import jdk.internal.org.objectweb.asm.*;
+import sun.misc.Unsafe;
+
import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.concurrent.atomic.AtomicInteger;
-import jdk.internal.org.objectweb.asm.*;
+
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.
@@ -41,6 +42,8 @@
* @see LambdaMetafactory
*/
/* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
+ private static final Unsafe UNSAFE = Unsafe.getUnsafe();
+
private static final int CLASSFILE_VERSION = 51;
private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
private static final String NAME_MAGIC_ACCESSOR_IMPL = "java/lang/invoke/MagicLambdaImpl";
@@ -77,36 +80,51 @@
private final Type[] instantiatedArgumentTypes; // ASM types for the functional interface arguments
/**
- * General meta-factory constructor, standard cases and allowing for uncommon options such as serialization.
+ * General meta-factory constructor, supporting both standard cases and
+ * allowing for uncommon options such as serialization or bridging.
*
- * @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges
- * of the caller.
- * @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.
- * @param markerInterfaces Additional interfaces which the lambda object should implement.
+ * @param caller Stacked automatically by VM; represents a lookup context
+ * with the accessibility privileges of the caller.
+ * @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 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 LambdaConversionException If any of the meta-factory protocol invariants are violated
+ * @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,
- int flags,
- Class<?>[] markerInterfaces)
+ boolean isSerializable,
+ Class<?>[] markerInterfaces,
+ MethodType[] additionalBridges)
throws ReflectiveOperationException, LambdaConversionException {
- super(caller, invokedType, samMethod, implMethod, instantiatedMethodType, flags, markerInterfaces);
+ super(caller, invokedType, samMethod, implMethod, instantiatedMethodType,
+ isSerializable, markerInterfaces, additionalBridges);
implMethodClassName = implDefiningClass.getName().replace('.', '/');
implMethodName = implInfo.getName();
implMethodDesc = implMethodType.toMethodDescriptorString();
@@ -134,7 +152,8 @@
* @return a CallSite, which, when invoked, will return an instance of the
* functional interface
* @throws ReflectiveOperationException
- * @throws LambdaConversionException If properly formed functional interface is not found
+ * @throws LambdaConversionException If properly formed functional interface
+ * is not found
*/
@Override
CallSite buildCallSite() throws ReflectiveOperationException, LambdaConversionException {
@@ -174,8 +193,16 @@
* Generate a class file which implements the functional
* 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
- * @throws LambdaConversionException If properly formed functional interface is not found
+ * @throws LambdaConversionException If properly formed functional interface
+ * is not found
*/
private Class<?> spinInnerClass() throws LambdaConversionException {
String samName = samBase.getName().replace('.', '/');
@@ -197,28 +224,22 @@
generateConstructor();
- MethodAnalyzer ma = new MethodAnalyzer();
-
// Forward the SAM method
- if (ma.getSamMethod() == null) {
- throw new LambdaConversionException(String.format("Functional interface method not found: %s", samMethodType));
- } else {
- generateForwardingMethod(ma.getSamMethod(), false);
- }
+ String methodDescriptor = samMethodType.toMethodDescriptorString();
+ MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samInfo.getName(), methodDescriptor, null, null);
+ new ForwardingMethodGenerator(mv).generate(methodDescriptor);
// Forward the bridges
- // @@@ 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);
+ if (additionalBridges != null) {
+ for (MethodType mt : additionalBridges) {
+ methodDescriptor = mt.toMethodDescriptorString();
+ mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samInfo.getName(), methodDescriptor, null, null);
+ new ForwardingMethodGenerator(mv).generate(methodDescriptor);
}
}
- if (isSerializable) {
+ if (isSerializable)
generateWriteReplace();
- }
cw.visitEnd();
@@ -247,8 +268,8 @@
}
);
- return (Class<?>) Unsafe.getUnsafe().defineClass(lambdaClassName, classBytes, 0, classBytes.length,
- loader, pd);
+ return UNSAFE.defineClass(lambdaClassName, classBytes, 0, classBytes.length,
+ loader, pd);
}
/**
@@ -265,7 +286,8 @@
ctor.visitVarInsn(ALOAD, 0);
ctor.visitVarInsn(argTypes[i].getOpcode(ILOAD), lvIndex + 1);
lvIndex += argTypes[i].getSize();
- ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor());
+ ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i],
+ argTypes[i].getDescriptor());
}
ctor.visitInsn(RETURN);
ctor.visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
@@ -283,7 +305,7 @@
mv.visitCode();
mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA);
- mv.visitInsn(DUP);;
+ mv.visitInsn(DUP);
mv.visitLdcInsn(Type.getType(targetClass));
mv.visitLdcInsn(samInfo.getReferenceKind());
mv.visitLdcInsn(invokedType.returnType().getName().replace('.', '/'));
@@ -313,24 +335,6 @@
}
/**
- * 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
* method, converting arguments, as needed.
*/
@@ -340,26 +344,26 @@
super(mv);
}
- void generate(Method m) throws InternalError {
+ void generate(String methodDescriptor) {
visitCode();
if (implKind == MethodHandleInfo.REF_newInvokeSpecial) {
visitTypeInsn(NEW, implMethodClassName);
- visitInsn(DUP);;
+ visitInsn(DUP);
}
for (int i = 0; i < argTypes.length; i++) {
visitVarInsn(ALOAD, 0);
visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor());
}
- convertArgumentTypes(Type.getArgumentTypes(m));
+ convertArgumentTypes(Type.getArgumentTypes(methodDescriptor));
// Invoke the method we want to forward to
visitMethodInsn(invocationOpcode(), implMethodClassName, implMethodName, implMethodDesc);
// 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
- Type samReturnType = Type.getReturnType(m);
+ Type samReturnType = Type.getReturnType(methodDescriptor);
convertType(implMethodReturnType, samReturnType, samReturnType);
visitInsn(samReturnType.getOpcode(Opcodes.IRETURN));
--- a/jdk/src/share/classes/java/lang/invoke/LambdaMetafactory.java Mon Jun 17 14:23:01 2013 +0100
+++ b/jdk/src/share/classes/java/lang/invoke/LambdaMetafactory.java Tue Jun 18 09:39:25 2013 +0100
@@ -25,6 +25,9 @@
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>
*
@@ -44,16 +47,11 @@
*
* <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
+ * {@code interface I<T> { int m(T x); }} 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 (Object)int} 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
- * methods because of the need for bridge methods. Invoking any of these methods on the lambda object will result
- * in invoking the implementation method.
+ * {@code (Byte)int}.
*
* <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
@@ -144,38 +142,59 @@
*/
public class LambdaMetafactory {
- /** Flag for alternate metafactories indicating the lambda object is must to be serializable */
+ /** 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
+ * Flag for alternate metafactories indicating the lambda object implements
+ * other marker interfaces
* besides Serializable
*/
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 MethodType[] EMPTY_MT_ARRAY = new MethodType[0];
-/**
- * Standard meta-factory for conversion of lambda expressions or method references to functional interfaces.
+ /**
+ * 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
- * of the caller.
- * @param invokedName Stacked automatically by VM; the name of the invoked method as it appears at the call site.
+ * @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
- * @return a CallSite, which, when invoked, will return an instance of the functional interface
+ * @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
+ * @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
+ * @throws LambdaConversionException If any of the meta-factory protocol
+ * invariants are violated
*/
public static CallSite metaFactory(MethodHandles.Lookup caller,
String invokedName,
@@ -185,15 +204,17 @@
MethodType instantiatedMethodType)
throws ReflectiveOperationException, LambdaConversionException {
AbstractValidatingLambdaMetafactory mf;
- mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod, implMethod, instantiatedMethodType,
- 0, EMPTY_CLASS_ARRAY);
+ mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod,
+ implMethod, instantiatedMethodType,
+ false, EMPTY_CLASS_ARRAY, EMPTY_MT_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.
+ * 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:
*
@@ -213,21 +234,28 @@
* int flags,
* int markerInterfaceCount, // 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 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 thefu
- * 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 args argument to pass, flags, marker interface count, and marker interfaces as described above
- * @return a CallSite, which, when invoked, will return an instance of the functional interface
+ * @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 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 LambdaConversionException If any of the meta-factory protocol invariants are violated
+ * @throws LambdaConversionException If any of the meta-factory protocol
+ * invariants are violated
*/
public static CallSite altMetaFactory(MethodHandles.Lookup caller,
String invokedName,
@@ -239,6 +267,7 @@
MethodType instantiatedMethodType = (MethodType)args[2];
int flags = (Integer) args[3];
Class<?>[] markerInterfaces;
+ MethodType[] bridges;
int argIndex = 4;
if ((flags & FLAG_MARKERS) != 0) {
int markerCount = (Integer) args[argIndex++];
@@ -248,9 +277,30 @@
}
else
markerInterfaces = EMPTY_CLASS_ARRAY;
- AbstractValidatingLambdaMetafactory mf;
- mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod, implMethod, instantiatedMethodType,
- flags, markerInterfaces);
+ if ((flags & FLAG_BRIDGES) != 0) {
+ int bridgeCount = (Integer) args[argIndex++];
+ bridges = new MethodType[bridgeCount];
+ 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();
return mf.buildCallSite();
}
--- a/jdk/src/share/classes/java/lang/invoke/MethodType.java Mon Jun 17 14:23:01 2013 +0100
+++ b/jdk/src/share/classes/java/lang/invoke/MethodType.java Tue Jun 18 09:39:25 2013 +0100
@@ -27,10 +27,13 @@
import sun.invoke.util.Wrapper;
import java.lang.ref.WeakReference;
+import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentHashMap;
import sun.invoke.util.BytecodeDescriptor;
import static java.lang.invoke.MethodHandleStatics.*;
import sun.invoke.util.VerifyType;
@@ -171,7 +174,7 @@
return new IndexOutOfBoundsException(num.toString());
}
- static final WeakInternSet internTable = new WeakInternSet();
+ static final ConcurrentWeakInternSet<MethodType> internTable = new ConcurrentWeakInternSet<>();
static final Class<?>[] NO_PTYPES = {};
@@ -1013,267 +1016,104 @@
}
/**
- * Weak intern set based on implementation of the <tt>HashSet</tt> and
- * <tt>WeakHashMap</tt>, with <em>weak values</em>. Note: <tt>null</tt>
- * values will yield <tt>NullPointerException</tt>
- * Refer to implementation of WeakInternSet for details.
+ * Simple implementation of weak concurrent intern set.
*
- * @see java.util.HashMap
- * @see java.util.HashSet
- * @see java.util.WeakHashMap
- * @see java.lang.ref.WeakReference
+ * @param <T> interned type
*/
- private static class WeakInternSet {
- // The default initial capacity -- MUST be a power of two.
- private static final int DEFAULT_INITIAL_CAPACITY = 16;
-
- // The maximum capacity, used if a higher value is implicitly specified
- // by either of the constructors with arguments.
- // MUST be a power of two <= 1<<30.
- private static final int MAXIMUM_CAPACITY = 1 << 30;
-
- // The load factor used when none specified in constructor.
- private static final float DEFAULT_LOAD_FACTOR = 0.75f;
-
- // The table, resized as necessary. Length MUST Always be a power of two.
- private Entry[] table;
-
- // The number of entries contained in this set.
- private int size;
-
- // The next size value at which to resize (capacity * load factor).
- private int threshold;
+ private static class ConcurrentWeakInternSet<T> {
- // The load factor for the hash table.
- private final float loadFactor;
-
- // Reference queue for cleared WeakEntries
- private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
-
- private Entry[] newTable(int n) {
- return new Entry[n];
- }
+ private final ConcurrentMap<WeakEntry<T>, WeakEntry<T>> map;
+ private final ReferenceQueue<T> stale;
- /**
- * Constructs a new, empty <tt>WeakInternSet</tt> with the default initial
- * capacity (16) and load factor (0.75).
- */
- WeakInternSet() {
- this.loadFactor = DEFAULT_LOAD_FACTOR;
- threshold = DEFAULT_INITIAL_CAPACITY;
- table = newTable(DEFAULT_INITIAL_CAPACITY);
- }
-
- /**
- * Applies a supplemental hash function to a given hashCode, which
- * defends against poor quality hash functions. This is critical
- * because hashing uses power-of-two length hash tables, that
- * otherwise encounter collisions for hashCodes that do not differ
- * in lower bits.
- * @param h preliminary hash code value
- * @return supplemental hash code value
- */
- private static int hash(int h) {
- // This function ensures that hashCodes that differ only by
- // constant multiples at each bit position have a bounded
- // number of collisions (approximately 8 at default load factor).
- h ^= (h >>> 20) ^ (h >>> 12);
- return h ^ (h >>> 7) ^ (h >>> 4);
+ public ConcurrentWeakInternSet() {
+ this.map = new ConcurrentHashMap<>();
+ this.stale = new ReferenceQueue<>();
}
/**
- * Checks for equality of non-null reference x and possibly-null y. By
- * default uses Object.equals.
- * @param x first object to compare
- * @param y second object to compare
- * @return <tt>true</tt> if objects are equal
- */
- private static boolean eq(Object x, Object y) {
- return x == y || x.equals(y);
- }
-
- /**
- * Returns index for hash code h.
- * @param h raw hash code
- * @param length length of table (power of 2)
- * @return index in table
- */
- private static int indexFor(int h, int length) {
- return h & (length-1);
- }
-
- /**
- * Expunges stale entries from the table.
+ * Get the existing interned element.
+ * This method returns null if no element is interned.
+ *
+ * @param elem element to look up
+ * @return the interned element
*/
- private void expungeStaleEntries() {
- for (Object x; (x = queue.poll()) != null; ) {
- synchronized (queue) {
- Entry entry = (Entry) x;
- int i = indexFor(entry.hash, table.length);
- Entry prev = table[i];
- Entry p = prev;
- while (p != null) {
- Entry next = p.next;
- if (p == entry) {
- if (prev == entry)
- table[i] = next;
- else
- prev.next = next;
- entry.next = null;
- size--;
- break;
- }
- prev = p;
- p = next;
- }
- }
- }
- }
+ public T get(T elem) {
+ if (elem == null) throw new NullPointerException();
+ expungeStaleElements();
- /**
- * Returns the table after first expunging stale entries.
- * @return an expunged hash table
- */
- private Entry[] getTable() {
- expungeStaleEntries();
- return table;
- }
-
- /**
- * Returns the entry to which the specified value is mapped,
- * or {@code null} if this set contains no entry for the value.
- *
- * <p>More formally, if this set contains an entry for value
- * {@code entry} to a value {@code value} such that
- * {@code entry.equals(value)}, then this method returns {@code entry};
- * otherwise it returns {@code null}.
- *
- * @param value value to search for in set
- * @return interned value if in set, otherwise <tt>null</tt>
- */
- synchronized MethodType get(MethodType value) {
- int h = hash(value.hashCode());
- Entry[] tab = getTable();
- int index = indexFor(h, tab.length);
- Entry e = tab[index];
- MethodType g;
- while (e != null) {
- if (e.hash == h && eq(value, g = e.get()))
- return g;
- e = e.next;
+ WeakEntry<T> value = map.get(new WeakEntry<>(elem));
+ if (value != null) {
+ T res = value.get();
+ if (res != null) {
+ return res;
+ }
}
return null;
}
/**
- * Attempts to add the specified value to the set and returns same value.
- * If the set previously contained an entry for this value, the old
- * value is left untouched and returned as the result.
+ * Interns the element.
+ * Always returns non-null element, matching the one in the intern set.
+ * Under the race against another add(), it can return <i>different</i>
+ * element, if another thread beats us to interning it.
*
- * @param value value to be added
- * @return the previous entry associated with <tt>value</tt>, or
- * <tt>value</tt> if there was no previous entry found
+ * @param elem element to add
+ * @return element that was actually added
*/
- synchronized MethodType add(MethodType value) {
- int h = hash(value.hashCode());
- Entry[] tab = getTable();
- int i = indexFor(h, tab.length);
- MethodType g;
- for (Entry e = tab[i]; e != null; e = e.next) {
- if (h == e.hash && eq(value, g = e.get())) {
- return g;
- }
- }
- Entry e = tab[i];
- tab[i] = new Entry(value, queue, h, e);
- if (++size >= threshold)
- resize(tab.length * 2);
- return value;
+ public T add(T elem) {
+ if (elem == null) throw new NullPointerException();
+
+ // Playing double race here, and so spinloop is required.
+ // First race is with two concurrent updaters.
+ // Second race is with GC purging weak ref under our feet.
+ // Hopefully, we almost always end up with a single pass.
+ T interned;
+ WeakEntry<T> e = new WeakEntry<>(elem, stale);
+ do {
+ expungeStaleElements();
+ WeakEntry<T> exist = map.putIfAbsent(e, e);
+ interned = (exist == null) ? elem : exist.get();
+ } while (interned == null);
+ return interned;
}
- /**
- * Rehashes the contents of this set into a new array with a
- * larger capacity. This method is called automatically when the
- * number of keys in this set reaches its threshold.
- *
- * If current capacity is MAXIMUM_CAPACITY, this method does not
- * resize the set, but sets threshold to Integer.MAX_VALUE.
- * This has the effect of preventing future calls.
- *
- * @param newCapacity the new capacity, MUST be a power of two;
- * must be greater than current capacity unless current
- * capacity is MAXIMUM_CAPACITY (in which case value
- * is irrelevant)
- */
- private void resize(int newCapacity) {
- Entry[] oldTable = getTable();
- int oldCapacity = oldTable.length;
- if (oldCapacity == MAXIMUM_CAPACITY) {
- threshold = Integer.MAX_VALUE;
- return;
- }
-
- Entry[] newTable = newTable(newCapacity);
- transfer(oldTable, newTable);
- table = newTable;
-
- /*
- * If ignoring null elements and processing ref queue caused massive
- * shrinkage, then restore old table. This should be rare, but avoids
- * unbounded expansion of garbage-filled tables.
- */
- if (size >= threshold / 2) {
- threshold = (int)(newCapacity * loadFactor);
- } else {
- expungeStaleEntries();
- transfer(newTable, oldTable);
- table = oldTable;
+ private void expungeStaleElements() {
+ Reference<? extends T> reference;
+ while ((reference = stale.poll()) != null) {
+ map.remove(reference);
}
}
- /**
- * Transfers all entries from src to dest tables
- * @param src original table
- * @param dest new table
- */
- private void transfer(Entry[] src, Entry[] dest) {
- for (int j = 0; j < src.length; ++j) {
- Entry e = src[j];
- src[j] = null;
- while (e != null) {
- Entry next = e.next;
- MethodType key = e.get();
- if (key == null) {
- e.next = null; // Help GC
- size--;
- } else {
- int i = indexFor(e.hash, dest.length);
- e.next = dest[i];
- dest[i] = e;
- }
- e = next;
+ private static class WeakEntry<T> extends WeakReference<T> {
+
+ public final int hashcode;
+
+ public WeakEntry(T key, ReferenceQueue<T> queue) {
+ super(key, queue);
+ hashcode = key.hashCode();
+ }
+
+ public WeakEntry(T key) {
+ super(key);
+ hashcode = key.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof WeakEntry) {
+ Object that = ((WeakEntry) obj).get();
+ Object mine = get();
+ return (that == null || mine == null) ? (this == obj) : mine.equals(that);
}
+ return false;
}
- }
-
- /**
- * The entries in this hash table extend WeakReference, using its main ref
- * field as the key.
- */
- private static class Entry extends WeakReference<MethodType> {
- final int hash;
- Entry next;
- /**
- * Creates new entry.
- */
- Entry(MethodType key,
- ReferenceQueue<Object> queue,
- int hash, Entry next) {
- super(key, queue);
- this.hash = hash;
- this.next = next;
+ @Override
+ public int hashCode() {
+ return hashcode;
}
+
}
}
+
}
--- a/jdk/src/share/classes/java/security/Signature.java Mon Jun 17 14:23:01 2013 +0100
+++ b/jdk/src/share/classes/java/security/Signature.java Tue Jun 18 09:39:25 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -248,6 +248,7 @@
Signature sig;
if (instance.impl instanceof Signature) {
sig = (Signature)instance.impl;
+ sig.algorithm = algorithm;
} else {
SignatureSpi spi = (SignatureSpi)instance.impl;
sig = new Delegate(spi, algorithm);
--- a/jdk/src/share/classes/sun/reflect/generics/repository/ClassRepository.java Mon Jun 17 14:23:01 2013 +0100
+++ b/jdk/src/share/classes/sun/reflect/generics/repository/ClassRepository.java Tue Jun 18 09:39:25 2013 +0100
@@ -40,6 +40,8 @@
*/
public class ClassRepository extends GenericDeclRepository<ClassSignature> {
+ public static final ClassRepository NONE = ClassRepository.make("Ljava/lang/Object;", null);
+
private Type superclass; // caches the generic superclass info
private Type[] superInterfaces; // caches the generic superinterface info
--- a/jdk/src/share/native/java/lang/Class.c Mon Jun 17 14:23:01 2013 +0100
+++ b/jdk/src/share/native/java/lang/Class.c Tue Jun 18 09:39:25 2013 +0100
@@ -55,7 +55,7 @@
static JNINativeMethod methods[] = {
{"getName0", "()" STR, (void *)&JVM_GetClassName},
{"getSuperclass", "()" CLS, NULL},
- {"getInterfaces", "()[" CLS, (void *)&JVM_GetClassInterfaces},
+ {"getInterfaces0", "()[" CLS, (void *)&JVM_GetClassInterfaces},
{"getClassLoader0", "()" JCL, (void *)&JVM_GetClassLoader},
{"isInterface", "()Z", (void *)&JVM_IsInterface},
{"getSigners", "()[" OBJ, (void *)&JVM_GetClassSigners},
@@ -70,7 +70,7 @@
{"getProtectionDomain0", "()" PD, (void *)&JVM_GetProtectionDomain},
{"getDeclaredClasses0", "()[" CLS, (void *)&JVM_GetDeclaredClasses},
{"getDeclaringClass", "()" CLS, (void *)&JVM_GetDeclaringClass},
- {"getGenericSignature", "()" STR, (void *)&JVM_GetClassSignature},
+ {"getGenericSignature0", "()" STR, (void *)&JVM_GetClassSignature},
{"getRawAnnotations", "()" BA, (void *)&JVM_GetClassAnnotations},
{"getConstantPool", "()" CPL, (void *)&JVM_GetClassConstantPool},
{"desiredAssertionStatus0","("CLS")Z",(void *)&JVM_DesiredAssertionStatus},
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/security/Signature/SignatureGetAlgorithm.java Tue Jun 18 09:39:25 2013 +0100
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+/*
+ * Portions Copyright (c) 2013 IBM Corporation
+ */
+
+/*
+ * @test
+ * @bug 8014620
+ * @summary Signature.getAlgorithm return null in special case
+ * @run main/othervm SignatureGetAlgorithm
+ * @author youdwei
+ */
+import java.security.*;
+
+public class SignatureGetAlgorithm {
+
+ public static void main(String[] args) throws Exception {
+ Provider testProvider = new TestProvider();
+ Security.addProvider(testProvider);
+ Signature sig = Signature.getInstance("MySignatureAlg");
+ String algorithm = sig.getAlgorithm();
+ System.out.println("Algorithm Name: " + algorithm);
+ if (algorithm == null) {
+ throw new Exception("algorithm name should be 'MySignatureAlg'");
+ }
+ }
+
+ public static class TestProvider extends Provider {
+ TestProvider() {
+ super("test", 1.0, "test");
+ put("Signature.MySignatureAlg",
+ "SignatureGetAlgorithm$MySignatureAlg");
+ }
+ }
+
+ public static class MySignatureAlg extends Signature {
+
+ public MySignatureAlg() {
+ super(null);
+ }
+
+ MySignatureAlg(String s) {
+ super(s);
+ }
+
+ @Override
+ protected void engineInitVerify(PublicKey publicKey)
+ throws InvalidKeyException {
+ }
+
+ @Override
+ protected void engineInitSign(PrivateKey privateKey)
+ throws InvalidKeyException {
+ }
+
+ @Override
+ protected void engineUpdate(byte b) throws SignatureException {
+ }
+
+ @Override
+ protected void engineUpdate(byte[] b, int off, int len)
+ throws SignatureException {
+ }
+
+ @Override
+ protected byte[] engineSign()
+ throws SignatureException {
+ return new byte[0];
+ }
+
+ @Override
+ protected boolean engineVerify(byte[] sigBytes)
+ throws SignatureException {
+ return false;
+ }
+
+ @Override
+ @Deprecated
+ protected void engineSetParameter(String param, Object value)
+ throws InvalidParameterException {
+ }
+
+ @Override
+ @Deprecated
+ protected Object engineGetParameter(String param)
+ throws InvalidParameterException {
+ return null;
+ }
+ }
+}