Merge
This commit is contained in:
commit
9735594f15
@ -708,8 +708,9 @@ public final class Class<T> implements java.io.Serializable,
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public TypeVariable<Class<T>>[] getTypeParameters() {
|
public TypeVariable<Class<T>>[] getTypeParameters() {
|
||||||
if (getGenericSignature() != null)
|
ClassRepository info = getGenericInfo();
|
||||||
return (TypeVariable<Class<T>>[])getGenericInfo().getTypeParameters();
|
if (info != null)
|
||||||
|
return (TypeVariable<Class<T>>[])info.getTypeParameters();
|
||||||
else
|
else
|
||||||
return (TypeVariable<Class<T>>[])new TypeVariable<?>[0];
|
return (TypeVariable<Class<T>>[])new TypeVariable<?>[0];
|
||||||
}
|
}
|
||||||
@ -759,15 +760,19 @@ public final class Class<T> implements java.io.Serializable,
|
|||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
public Type getGenericSuperclass() {
|
public Type getGenericSuperclass() {
|
||||||
if (getGenericSignature() != null) {
|
ClassRepository info = getGenericInfo();
|
||||||
|
if (info == null) {
|
||||||
|
return getSuperclass();
|
||||||
|
}
|
||||||
|
|
||||||
// Historical irregularity:
|
// Historical irregularity:
|
||||||
// Generic signature marks interfaces with superclass = Object
|
// Generic signature marks interfaces with superclass = Object
|
||||||
// but this API returns null for interfaces
|
// but this API returns null for interfaces
|
||||||
if (isInterface())
|
if (isInterface()) {
|
||||||
return null;
|
return null;
|
||||||
return getGenericInfo().getSuperclass();
|
}
|
||||||
} else
|
|
||||||
return getSuperclass();
|
return info.getSuperclass();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -830,7 +835,23 @@ public final class Class<T> implements java.io.Serializable,
|
|||||||
*
|
*
|
||||||
* @return an array of interfaces implemented by this class.
|
* @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
|
* Returns the {@code Type}s representing the interfaces
|
||||||
@ -882,10 +903,8 @@ public final class Class<T> implements java.io.Serializable,
|
|||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
public Type[] getGenericInterfaces() {
|
public Type[] getGenericInterfaces() {
|
||||||
if (getGenericSignature() != null)
|
ClassRepository info = getGenericInfo();
|
||||||
return getGenericInfo().getSuperInterfaces();
|
return (info == null) ? getInterfaces() : info.getSuperInterfaces();
|
||||||
else
|
|
||||||
return getInterfaces();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2396,6 +2415,8 @@ public final class Class<T> implements java.io.Serializable,
|
|||||||
// Intermediate results for getFields and getMethods
|
// Intermediate results for getFields and getMethods
|
||||||
volatile Field[] declaredPublicFields;
|
volatile Field[] declaredPublicFields;
|
||||||
volatile Method[] declaredPublicMethods;
|
volatile Method[] declaredPublicMethods;
|
||||||
|
volatile Class<?>[] interfaces;
|
||||||
|
|
||||||
// Value of classRedefinedCount when we created this ReflectionData instance
|
// Value of classRedefinedCount when we created this ReflectionData instance
|
||||||
final int redefinedCount;
|
final int redefinedCount;
|
||||||
|
|
||||||
@ -2471,10 +2492,10 @@ public final class Class<T> implements java.io.Serializable,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generic signature handling
|
// Generic signature handling
|
||||||
private native String getGenericSignature();
|
private native String getGenericSignature0();
|
||||||
|
|
||||||
// Generic info repository; lazily initialized
|
// Generic info repository; lazily initialized
|
||||||
private transient ClassRepository genericInfo;
|
private volatile transient ClassRepository genericInfo;
|
||||||
|
|
||||||
// accessor for factory
|
// accessor for factory
|
||||||
private GenericsFactory getFactory() {
|
private GenericsFactory getFactory() {
|
||||||
@ -2482,15 +2503,20 @@ public final class Class<T> implements java.io.Serializable,
|
|||||||
return CoreReflectionFactory.make(this, ClassScope.make(this));
|
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() {
|
private ClassRepository getGenericInfo() {
|
||||||
// lazily initialize repository if necessary
|
ClassRepository genericInfo = this.genericInfo;
|
||||||
if (genericInfo == null) {
|
if (genericInfo == null) {
|
||||||
// create and cache generic info repository
|
String signature = getGenericSignature0();
|
||||||
genericInfo = ClassRepository.make(getGenericSignature(),
|
if (signature == null) {
|
||||||
getFactory());
|
genericInfo = ClassRepository.NONE;
|
||||||
|
} else {
|
||||||
|
genericInfo = ClassRepository.make(signature, getFactory());
|
||||||
}
|
}
|
||||||
return genericInfo; //return cached repository
|
this.genericInfo = genericInfo;
|
||||||
|
}
|
||||||
|
return (genericInfo != ClassRepository.NONE) ? genericInfo : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Annotations handling
|
// Annotations handling
|
||||||
|
@ -24,14 +24,11 @@
|
|||||||
*/
|
*/
|
||||||
package java.lang.invoke;
|
package java.lang.invoke;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import sun.invoke.util.Wrapper;
|
import sun.invoke.util.Wrapper;
|
||||||
import static sun.invoke.util.Wrapper.*;
|
|
||||||
|
import static sun.invoke.util.Wrapper.forPrimitiveType;
|
||||||
|
import static sun.invoke.util.Wrapper.forWrapperType;
|
||||||
|
import static sun.invoke.util.Wrapper.isWrapperType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract implementation of a lambda metafactory which provides parameter unrolling and input validation.
|
* Abstract implementation of a lambda metafactory which provides parameter unrolling and input validation.
|
||||||
@ -67,34 +64,52 @@ import static sun.invoke.util.Wrapper.*;
|
|||||||
final MethodType instantiatedMethodType; // Instantiated erased functional interface method type "(Integer)Object"
|
final MethodType instantiatedMethodType; // Instantiated erased functional interface method type "(Integer)Object"
|
||||||
final boolean isSerializable; // Should the returned instance be serializable
|
final boolean isSerializable; // Should the returned instance be serializable
|
||||||
final Class<?>[] markerInterfaces; // Additional marker interfaces to be implemented
|
final Class<?>[] markerInterfaces; // Additional marker interfaces to be implemented
|
||||||
|
final MethodType[] additionalBridges; // Signatures of additional methods to bridge
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Meta-factory constructor.
|
* Meta-factory constructor.
|
||||||
*
|
*
|
||||||
* @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges
|
* @param caller Stacked automatically by VM; represents a lookup context
|
||||||
* of the caller.
|
* with the accessibility privileges of the caller.
|
||||||
* @param invokedType Stacked automatically by VM; the signature of the invoked method, which includes the
|
* @param invokedType Stacked automatically by VM; the signature of the
|
||||||
* expected static type of the returned lambda object, and the static types of the captured
|
* invoked method, which includes the expected static
|
||||||
* arguments for the lambda. In the event that the implementation method is an instance method,
|
* type of the returned lambda object, and the static
|
||||||
* the first argument in the invocation signature will correspond to the receiver.
|
* types of the captured arguments for the lambda. In
|
||||||
* @param samMethod The primary method in the functional interface to which the lambda or method reference is
|
* the event that the implementation method is an
|
||||||
* being converted, represented as a method handle.
|
* instance method, the first argument in the invocation
|
||||||
* @param implMethod The implementation method which should be called (with suitable adaptation of argument
|
* signature will correspond to the receiver.
|
||||||
* types, return types, and adjustment for captured arguments) when methods of the resulting
|
* @param samMethod The primary method in the functional interface to which
|
||||||
* functional interface instance are invoked.
|
* the lambda or method reference is being converted,
|
||||||
* @param instantiatedMethodType The signature of the primary functional interface method after type variables
|
* represented as a method handle.
|
||||||
* are substituted with their instantiation from the capture site
|
* @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 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,
|
AbstractValidatingLambdaMetafactory(MethodHandles.Lookup caller,
|
||||||
MethodType invokedType,
|
MethodType invokedType,
|
||||||
MethodHandle samMethod,
|
MethodHandle samMethod,
|
||||||
MethodHandle implMethod,
|
MethodHandle implMethod,
|
||||||
MethodType instantiatedMethodType,
|
MethodType instantiatedMethodType,
|
||||||
int flags,
|
boolean isSerializable,
|
||||||
Class<?>[] markerInterfaces)
|
Class<?>[] markerInterfaces,
|
||||||
|
MethodType[] additionalBridges)
|
||||||
throws ReflectiveOperationException, LambdaConversionException {
|
throws ReflectiveOperationException, LambdaConversionException {
|
||||||
this.targetClass = caller.lookupClass();
|
this.targetClass = caller.lookupClass();
|
||||||
this.invokedType = invokedType;
|
this.invokedType = invokedType;
|
||||||
@ -118,32 +133,22 @@ import static sun.invoke.util.Wrapper.*;
|
|||||||
implKind == MethodHandleInfo.REF_invokeInterface;
|
implKind == MethodHandleInfo.REF_invokeInterface;
|
||||||
this.implDefiningClass = implInfo.getDeclaringClass();
|
this.implDefiningClass = implInfo.getDeclaringClass();
|
||||||
this.implMethodType = implInfo.getMethodType();
|
this.implMethodType = implInfo.getMethodType();
|
||||||
|
|
||||||
this.instantiatedMethodType = instantiatedMethodType;
|
this.instantiatedMethodType = instantiatedMethodType;
|
||||||
|
this.isSerializable = isSerializable;
|
||||||
|
this.markerInterfaces = markerInterfaces;
|
||||||
|
this.additionalBridges = additionalBridges;
|
||||||
|
|
||||||
if (!samClass.isInterface()) {
|
if (!samClass.isInterface()) {
|
||||||
throw new LambdaConversionException(String.format(
|
throw new LambdaConversionException(String.format(
|
||||||
"Functional interface %s is not an interface",
|
"Functional interface %s is not an interface", samClass.getName()));
|
||||||
samClass.getName()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean foundSerializableSupertype = Serializable.class.isAssignableFrom(samBase);
|
|
||||||
for (Class<?> c : markerInterfaces) {
|
for (Class<?> c : markerInterfaces) {
|
||||||
if (!c.isInterface()) {
|
if (!c.isInterface()) {
|
||||||
throw new LambdaConversionException(String.format(
|
throw new LambdaConversionException(String.format(
|
||||||
"Marker interface %s is not an interface",
|
"Marker interface %s is not an interface", c.getName()));
|
||||||
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 @@ import static sun.invoke.util.Wrapper.*;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check type adaptability
|
* Check type adaptability for parameter types.
|
||||||
* @param fromType
|
* @param fromType Type to convert from
|
||||||
* @param toType
|
* @param toType Type to convert to
|
||||||
* @param strict If true, do strict checks, else allow that fromType may be parameterized
|
* @param strict If true, do strict checks, else allow that fromType may be parameterized
|
||||||
* @return True if 'fromType' can be passed to an argument of 'toType'
|
* @return True if 'fromType' can be passed to an argument of 'toType'
|
||||||
*/
|
*/
|
||||||
@ -299,15 +304,14 @@ import static sun.invoke.util.Wrapper.*;
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// both are reference types: fromType should be a superclass of toType.
|
// both are reference types: fromType should be a superclass of toType.
|
||||||
return strict? toType.isAssignableFrom(fromType) : true;
|
return !strict || toType.isAssignableFrom(fromType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check type adaptability for return types -- special handling of void type) and parameterized fromType
|
* Check type adaptability for return types -- special handling of void type)
|
||||||
* @param fromType
|
* and parameterized fromType
|
||||||
* @param toType
|
|
||||||
* @return True if 'fromType' can be converted to 'toType'
|
* @return True if 'fromType' can be converted to 'toType'
|
||||||
*/
|
*/
|
||||||
private boolean isAdaptableToAsReturn(Class<?> fromType, Class<?> toType) {
|
private boolean isAdaptableToAsReturn(Class<?> fromType, Class<?> toType) {
|
||||||
@ -338,89 +342,4 @@ import static sun.invoke.util.Wrapper.*;
|
|||||||
}
|
}
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
/**
|
|
||||||
* Find the functional interface method and corresponding abstract methods
|
|
||||||
* which should be bridged. The functional interface method and those to be
|
|
||||||
* bridged will have the same name and number of parameters. Check for
|
|
||||||
* matching default methods (non-abstract), the VM will create bridges for
|
|
||||||
* default methods; We don't have enough readily available type information
|
|
||||||
* to distinguish between where the functional interface method should be
|
|
||||||
* bridged and where the default method should be bridged; This situation is
|
|
||||||
* flagged.
|
|
||||||
*/
|
|
||||||
class MethodAnalyzer {
|
|
||||||
private final Method[] methods = samBase.getMethods();
|
|
||||||
|
|
||||||
private Method samMethod = null;
|
|
||||||
private final List<Method> methodsToBridge = new ArrayList<>(methods.length);
|
|
||||||
private boolean conflictFoundBetweenDefaultAndBridge = false;
|
|
||||||
|
|
||||||
MethodAnalyzer() {
|
|
||||||
String samMethodName = samInfo.getName();
|
|
||||||
Class<?>[] samParamTypes = samMethodType.parameterArray();
|
|
||||||
int samParamLength = samParamTypes.length;
|
|
||||||
Class<?> samReturnType = samMethodType.returnType();
|
|
||||||
Class<?> objectClass = Object.class;
|
|
||||||
List<Method> defaultMethods = new ArrayList<>(methods.length);
|
|
||||||
|
|
||||||
for (Method m : methods) {
|
|
||||||
if (m.getName().equals(samMethodName) && m.getDeclaringClass() != objectClass) {
|
|
||||||
Class<?>[] mParamTypes = m.getParameterTypes();
|
|
||||||
if (mParamTypes.length == samParamLength) {
|
|
||||||
// Method matches name and parameter length -- and is not Object
|
|
||||||
if (Modifier.isAbstract(m.getModifiers())) {
|
|
||||||
// Method is abstract
|
|
||||||
if (m.getReturnType().equals(samReturnType)
|
|
||||||
&& Arrays.equals(mParamTypes, samParamTypes)) {
|
|
||||||
// Exact match, this is the SAM method signature
|
|
||||||
samMethod = m;
|
|
||||||
} else if (!hasMatchingBridgeSignature(m)) {
|
|
||||||
// Record bridges, exclude methods with duplicate signatures
|
|
||||||
methodsToBridge.add(m);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Record default methods for conflict testing
|
|
||||||
defaultMethods.add(m);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (Method dm : defaultMethods) {
|
|
||||||
if (hasMatchingBridgeSignature(dm)) {
|
|
||||||
conflictFoundBetweenDefaultAndBridge = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Method getSamMethod() {
|
|
||||||
return samMethod;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Method> getMethodsToBridge() {
|
|
||||||
return methodsToBridge;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean conflictFoundBetweenDefaultAndBridge() {
|
|
||||||
return conflictFoundBetweenDefaultAndBridge;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Search the list of previously found bridge methods to determine if there is a method with the same signature
|
|
||||||
* (return and parameter types) as the specified method.
|
|
||||||
*
|
|
||||||
* @param m The method to match
|
|
||||||
* @return True if the method was found, False otherwise
|
|
||||||
*/
|
|
||||||
private boolean hasMatchingBridgeSignature(Method m) {
|
|
||||||
Class<?>[] ptypes = m.getParameterTypes();
|
|
||||||
Class<?> rtype = m.getReturnType();
|
|
||||||
for (Method md : methodsToBridge) {
|
|
||||||
if (md.getReturnType().equals(rtype) && Arrays.equals(ptypes, md.getParameterTypes())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -25,15 +25,16 @@
|
|||||||
|
|
||||||
package java.lang.invoke;
|
package java.lang.invoke;
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.security.ProtectionDomain;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import jdk.internal.org.objectweb.asm.*;
|
import jdk.internal.org.objectweb.asm.*;
|
||||||
import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
|
||||||
import sun.misc.Unsafe;
|
import sun.misc.Unsafe;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
import java.security.AccessController;
|
import java.security.AccessController;
|
||||||
import java.security.PrivilegedAction;
|
import java.security.PrivilegedAction;
|
||||||
|
import java.security.ProtectionDomain;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lambda metafactory implementation which dynamically creates an inner-class-like class per lambda callsite.
|
* Lambda metafactory implementation which dynamically creates an inner-class-like class per lambda callsite.
|
||||||
@ -41,6 +42,8 @@ import java.security.PrivilegedAction;
|
|||||||
* @see LambdaMetafactory
|
* @see LambdaMetafactory
|
||||||
*/
|
*/
|
||||||
/* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
|
/* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
|
||||||
|
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
|
||||||
|
|
||||||
private static final int CLASSFILE_VERSION = 51;
|
private static final int CLASSFILE_VERSION = 51;
|
||||||
private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
|
private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
|
||||||
private static final String NAME_MAGIC_ACCESSOR_IMPL = "java/lang/invoke/MagicLambdaImpl";
|
private static final String NAME_MAGIC_ACCESSOR_IMPL = "java/lang/invoke/MagicLambdaImpl";
|
||||||
@ -77,36 +80,51 @@ import java.security.PrivilegedAction;
|
|||||||
private final Type[] instantiatedArgumentTypes; // ASM types for the functional interface arguments
|
private final Type[] instantiatedArgumentTypes; // ASM types for the functional interface arguments
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* General meta-factory constructor, 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
|
* @param caller Stacked automatically by VM; represents a lookup context
|
||||||
* of the caller.
|
* with the accessibility privileges of the caller.
|
||||||
* @param invokedType Stacked automatically by VM; the signature of the invoked method, which includes the
|
* @param invokedType Stacked automatically by VM; the signature of the
|
||||||
* expected static type of the returned lambda object, and the static types of the captured
|
* invoked method, which includes the expected static
|
||||||
* arguments for the lambda. In the event that the implementation method is an instance method,
|
* type of the returned lambda object, and the static
|
||||||
* the first argument in the invocation signature will correspond to the receiver.
|
* types of the captured arguments for the lambda. In
|
||||||
* @param samMethod The primary method in the functional interface to which the lambda or method reference is
|
* the event that the implementation method is an
|
||||||
* being converted, represented as a method handle.
|
* instance method, the first argument in the invocation
|
||||||
* @param implMethod The implementation method which should be called (with suitable adaptation of argument
|
* signature will correspond to the receiver.
|
||||||
* types, return types, and adjustment for captured arguments) when methods of the resulting
|
* @param samMethod The primary method in the functional interface to which
|
||||||
* functional interface instance are invoked.
|
* the lambda or method reference is being converted,
|
||||||
* @param instantiatedMethodType The signature of the primary functional interface method after type variables
|
* represented as a method handle.
|
||||||
* are substituted with their instantiation from the capture site
|
* @param implMethod The implementation method which should be called (with
|
||||||
* @param flags A bitmask containing flags that may influence the translation of this lambda expression. Defined
|
* suitable adaptation of argument types, return types,
|
||||||
* fields include FLAG_SERIALIZABLE.
|
* and adjustment for captured arguments) when methods of
|
||||||
* @param markerInterfaces Additional interfaces which the lambda object should implement.
|
* the resulting functional interface instance are invoked.
|
||||||
|
* @param instantiatedMethodType The signature of the primary functional
|
||||||
|
* interface method after type variables are
|
||||||
|
* substituted with their instantiation from
|
||||||
|
* the capture site
|
||||||
|
* @param isSerializable Should the lambda be made serializable? If set,
|
||||||
|
* either the target type or one of the additional SAM
|
||||||
|
* types must extend {@code Serializable}.
|
||||||
|
* @param markerInterfaces Additional interfaces which the lambda object
|
||||||
|
* should implement.
|
||||||
|
* @param additionalBridges Method types for additional signatures to be
|
||||||
|
* bridged to the implementation method
|
||||||
* @throws ReflectiveOperationException
|
* @throws ReflectiveOperationException
|
||||||
* @throws LambdaConversionException If any of the meta-factory protocol invariants are violated
|
* @throws LambdaConversionException If any of the meta-factory protocol
|
||||||
|
* invariants are violated
|
||||||
*/
|
*/
|
||||||
public InnerClassLambdaMetafactory(MethodHandles.Lookup caller,
|
public InnerClassLambdaMetafactory(MethodHandles.Lookup caller,
|
||||||
MethodType invokedType,
|
MethodType invokedType,
|
||||||
MethodHandle samMethod,
|
MethodHandle samMethod,
|
||||||
MethodHandle implMethod,
|
MethodHandle implMethod,
|
||||||
MethodType instantiatedMethodType,
|
MethodType instantiatedMethodType,
|
||||||
int flags,
|
boolean isSerializable,
|
||||||
Class<?>[] markerInterfaces)
|
Class<?>[] markerInterfaces,
|
||||||
|
MethodType[] additionalBridges)
|
||||||
throws ReflectiveOperationException, LambdaConversionException {
|
throws ReflectiveOperationException, LambdaConversionException {
|
||||||
super(caller, invokedType, samMethod, implMethod, instantiatedMethodType, flags, markerInterfaces);
|
super(caller, invokedType, samMethod, implMethod, instantiatedMethodType,
|
||||||
|
isSerializable, markerInterfaces, additionalBridges);
|
||||||
implMethodClassName = implDefiningClass.getName().replace('.', '/');
|
implMethodClassName = implDefiningClass.getName().replace('.', '/');
|
||||||
implMethodName = implInfo.getName();
|
implMethodName = implInfo.getName();
|
||||||
implMethodDesc = implMethodType.toMethodDescriptorString();
|
implMethodDesc = implMethodType.toMethodDescriptorString();
|
||||||
@ -134,7 +152,8 @@ import java.security.PrivilegedAction;
|
|||||||
* @return a CallSite, which, when invoked, will return an instance of the
|
* @return a CallSite, which, when invoked, will return an instance of the
|
||||||
* functional interface
|
* functional interface
|
||||||
* @throws ReflectiveOperationException
|
* @throws ReflectiveOperationException
|
||||||
* @throws LambdaConversionException If properly formed functional interface is not found
|
* @throws LambdaConversionException If properly formed functional interface
|
||||||
|
* is not found
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
CallSite buildCallSite() throws ReflectiveOperationException, LambdaConversionException {
|
CallSite buildCallSite() throws ReflectiveOperationException, LambdaConversionException {
|
||||||
@ -174,8 +193,16 @@ import java.security.PrivilegedAction;
|
|||||||
* Generate a class file which implements the functional
|
* Generate a class file which implements the functional
|
||||||
* interface, define and return the class.
|
* interface, define and return the class.
|
||||||
*
|
*
|
||||||
|
* @implNote The class that is generated does not include signature
|
||||||
|
* information for exceptions that may be present on the SAM method.
|
||||||
|
* This is to reduce classfile size, and is harmless as checked exceptions
|
||||||
|
* are erased anyway, no one will ever compile against this classfile,
|
||||||
|
* and we make no guarantees about the reflective properties of lambda
|
||||||
|
* objects.
|
||||||
|
*
|
||||||
* @return a Class which implements the functional interface
|
* @return a Class which implements the functional interface
|
||||||
* @throws LambdaConversionException If properly formed functional interface is not found
|
* @throws LambdaConversionException If properly formed functional interface
|
||||||
|
* is not found
|
||||||
*/
|
*/
|
||||||
private Class<?> spinInnerClass() throws LambdaConversionException {
|
private Class<?> spinInnerClass() throws LambdaConversionException {
|
||||||
String samName = samBase.getName().replace('.', '/');
|
String samName = samBase.getName().replace('.', '/');
|
||||||
@ -197,28 +224,22 @@ import java.security.PrivilegedAction;
|
|||||||
|
|
||||||
generateConstructor();
|
generateConstructor();
|
||||||
|
|
||||||
MethodAnalyzer ma = new MethodAnalyzer();
|
|
||||||
|
|
||||||
// Forward the SAM method
|
// Forward the SAM method
|
||||||
if (ma.getSamMethod() == null) {
|
String methodDescriptor = samMethodType.toMethodDescriptorString();
|
||||||
throw new LambdaConversionException(String.format("Functional interface method not found: %s", samMethodType));
|
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samInfo.getName(), methodDescriptor, null, null);
|
||||||
} else {
|
new ForwardingMethodGenerator(mv).generate(methodDescriptor);
|
||||||
generateForwardingMethod(ma.getSamMethod(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forward the bridges
|
// Forward the bridges
|
||||||
// @@@ The commented-out code is temporary, pending the VM's ability to bridge all methods on request
|
if (additionalBridges != null) {
|
||||||
// @@@ Once the VM can do fail-over, uncomment the !ma.wasDefaultMethodFound() test, and emit the appropriate
|
for (MethodType mt : additionalBridges) {
|
||||||
// @@@ classfile attribute to request custom bridging. See 8002092.
|
methodDescriptor = mt.toMethodDescriptorString();
|
||||||
if (!ma.getMethodsToBridge().isEmpty() /* && !ma.conflictFoundBetweenDefaultAndBridge() */ ) {
|
mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samInfo.getName(), methodDescriptor, null, null);
|
||||||
for (Method m : ma.getMethodsToBridge()) {
|
new ForwardingMethodGenerator(mv).generate(methodDescriptor);
|
||||||
generateForwardingMethod(m, true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isSerializable) {
|
if (isSerializable)
|
||||||
generateWriteReplace();
|
generateWriteReplace();
|
||||||
}
|
|
||||||
|
|
||||||
cw.visitEnd();
|
cw.visitEnd();
|
||||||
|
|
||||||
@ -247,7 +268,7 @@ import java.security.PrivilegedAction;
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return (Class<?>) Unsafe.getUnsafe().defineClass(lambdaClassName, classBytes, 0, classBytes.length,
|
return UNSAFE.defineClass(lambdaClassName, classBytes, 0, classBytes.length,
|
||||||
loader, pd);
|
loader, pd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,7 +286,8 @@ import java.security.PrivilegedAction;
|
|||||||
ctor.visitVarInsn(ALOAD, 0);
|
ctor.visitVarInsn(ALOAD, 0);
|
||||||
ctor.visitVarInsn(argTypes[i].getOpcode(ILOAD), lvIndex + 1);
|
ctor.visitVarInsn(argTypes[i].getOpcode(ILOAD), lvIndex + 1);
|
||||||
lvIndex += argTypes[i].getSize();
|
lvIndex += argTypes[i].getSize();
|
||||||
ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor());
|
ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i],
|
||||||
|
argTypes[i].getDescriptor());
|
||||||
}
|
}
|
||||||
ctor.visitInsn(RETURN);
|
ctor.visitInsn(RETURN);
|
||||||
ctor.visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
|
ctor.visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
|
||||||
@ -283,7 +305,7 @@ import java.security.PrivilegedAction;
|
|||||||
|
|
||||||
mv.visitCode();
|
mv.visitCode();
|
||||||
mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA);
|
mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA);
|
||||||
mv.visitInsn(DUP);;
|
mv.visitInsn(DUP);
|
||||||
mv.visitLdcInsn(Type.getType(targetClass));
|
mv.visitLdcInsn(Type.getType(targetClass));
|
||||||
mv.visitLdcInsn(samInfo.getReferenceKind());
|
mv.visitLdcInsn(samInfo.getReferenceKind());
|
||||||
mv.visitLdcInsn(invokedType.returnType().getName().replace('.', '/'));
|
mv.visitLdcInsn(invokedType.returnType().getName().replace('.', '/'));
|
||||||
@ -312,24 +334,6 @@ import java.security.PrivilegedAction;
|
|||||||
mv.visitEnd();
|
mv.visitEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a method which calls the lambda implementation method,
|
|
||||||
* converting arguments, as needed.
|
|
||||||
* @param m The method whose signature should be generated
|
|
||||||
* @param isBridge True if this methods should be flagged as a bridge
|
|
||||||
*/
|
|
||||||
private void generateForwardingMethod(Method m, boolean isBridge) {
|
|
||||||
Class<?>[] exceptionTypes = m.getExceptionTypes();
|
|
||||||
String[] exceptionNames = new String[exceptionTypes.length];
|
|
||||||
for (int i = 0; i < exceptionTypes.length; i++) {
|
|
||||||
exceptionNames[i] = exceptionTypes[i].getName().replace('.', '/');
|
|
||||||
}
|
|
||||||
String methodDescriptor = Type.getMethodDescriptor(m);
|
|
||||||
int access = isBridge? ACC_PUBLIC | ACC_BRIDGE : ACC_PUBLIC;
|
|
||||||
MethodVisitor mv = cw.visitMethod(access, m.getName(), methodDescriptor, null, exceptionNames);
|
|
||||||
new ForwardingMethodGenerator(mv).generate(m);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class generates a method body which calls the lambda implementation
|
* This class generates a method body which calls the lambda implementation
|
||||||
* method, converting arguments, as needed.
|
* method, converting arguments, as needed.
|
||||||
@ -340,26 +344,26 @@ import java.security.PrivilegedAction;
|
|||||||
super(mv);
|
super(mv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate(Method m) throws InternalError {
|
void generate(String methodDescriptor) {
|
||||||
visitCode();
|
visitCode();
|
||||||
|
|
||||||
if (implKind == MethodHandleInfo.REF_newInvokeSpecial) {
|
if (implKind == MethodHandleInfo.REF_newInvokeSpecial) {
|
||||||
visitTypeInsn(NEW, implMethodClassName);
|
visitTypeInsn(NEW, implMethodClassName);
|
||||||
visitInsn(DUP);;
|
visitInsn(DUP);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < argTypes.length; i++) {
|
for (int i = 0; i < argTypes.length; i++) {
|
||||||
visitVarInsn(ALOAD, 0);
|
visitVarInsn(ALOAD, 0);
|
||||||
visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor());
|
visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor());
|
||||||
}
|
}
|
||||||
|
|
||||||
convertArgumentTypes(Type.getArgumentTypes(m));
|
convertArgumentTypes(Type.getArgumentTypes(methodDescriptor));
|
||||||
|
|
||||||
// Invoke the method we want to forward to
|
// Invoke the method we want to forward to
|
||||||
visitMethodInsn(invocationOpcode(), implMethodClassName, implMethodName, implMethodDesc);
|
visitMethodInsn(invocationOpcode(), implMethodClassName, implMethodName, implMethodDesc);
|
||||||
|
|
||||||
// Convert the return value (if any) and return it
|
// Convert the return value (if any) and return it
|
||||||
// Note: if adapting from non-void to void, the 'return' instruction will pop the unneeded result
|
// Note: if adapting from non-void to void, the 'return' instruction will pop the unneeded result
|
||||||
Type samReturnType = Type.getReturnType(m);
|
Type samReturnType = Type.getReturnType(methodDescriptor);
|
||||||
convertType(implMethodReturnType, samReturnType, samReturnType);
|
convertType(implMethodReturnType, samReturnType, samReturnType);
|
||||||
visitInsn(samReturnType.getOpcode(Opcodes.IRETURN));
|
visitInsn(samReturnType.getOpcode(Opcodes.IRETURN));
|
||||||
|
|
||||||
|
@ -25,6 +25,9 @@
|
|||||||
|
|
||||||
package java.lang.invoke;
|
package java.lang.invoke;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Bootstrap methods for converting lambda expressions and method references to functional interface objects.</p>
|
* <p>Bootstrap methods for converting lambda expressions and method references to functional interface objects.</p>
|
||||||
*
|
*
|
||||||
@ -44,16 +47,11 @@ package java.lang.invoke;
|
|||||||
*
|
*
|
||||||
* <p>When parameterized types are used, the instantiated type of the functional interface method may be different
|
* <p>When parameterized types are used, the instantiated type of the functional interface method may be different
|
||||||
* from that in the functional interface. For example, consider
|
* from that in the functional interface. For example, consider
|
||||||
* <code>interface I<T> { int m(T x); }</code> if this functional interface type is used in a lambda
|
* {@code interface I<T> { int m(T x); }} 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 I<Byte>; v = ...}, 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 (Object)int} and the erased instantiated type of the functional interface method (or simply
|
||||||
* <I>instantiated method type</I>), which has signature
|
* <I>instantiated method type</I>), which has signature
|
||||||
* <code>(Byte)int</code>.
|
* {@code (Byte)int}.
|
||||||
*
|
|
||||||
* <p>While functional interfaces only have a single abstract method from the language perspective (concrete
|
|
||||||
* methods in Object are and default methods may be present), at the bytecode level they may actually have multiple
|
|
||||||
* methods because of the need for bridge methods. Invoking any of these methods on the lambda object will result
|
|
||||||
* in invoking the implementation method.
|
|
||||||
*
|
*
|
||||||
* <p>The argument list of the implementation method and the argument list of the functional interface method(s)
|
* <p>The argument list of the implementation method and the argument list of the functional interface method(s)
|
||||||
* may differ in several ways. The implementation methods may have additional arguments to accommodate arguments
|
* may differ in several ways. The implementation methods may have additional arguments to accommodate arguments
|
||||||
@ -144,38 +142,59 @@ package java.lang.invoke;
|
|||||||
*/
|
*/
|
||||||
public class LambdaMetafactory {
|
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;
|
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
|
* besides Serializable
|
||||||
*/
|
*/
|
||||||
public static final int FLAG_MARKERS = 1 << 1;
|
public static final int FLAG_MARKERS = 1 << 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag for alternate metafactories indicating the lambda object requires
|
||||||
|
* additional bridge methods
|
||||||
|
*/
|
||||||
|
public static final int FLAG_BRIDGES = 1 << 2;
|
||||||
|
|
||||||
private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
|
private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
|
||||||
|
private static final MethodType[] EMPTY_MT_ARRAY = new MethodType[0];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Standard meta-factory for conversion of lambda expressions or method 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
|
* @param caller Stacked automatically by VM; represents a lookup context
|
||||||
* of the caller.
|
* 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 invokedName Stacked automatically by VM; the name of the invoked
|
||||||
|
* method as it appears at the call site.
|
||||||
* Currently unused.
|
* Currently unused.
|
||||||
* @param invokedType Stacked automatically by VM; the signature of the invoked method, which includes the
|
* @param invokedType Stacked automatically by VM; the signature of the
|
||||||
* expected static type of the returned lambda object, and the static types of the captured
|
* invoked method, which includes the expected static
|
||||||
* arguments for the lambda. In the event that the implementation method is an instance method,
|
* type of the returned lambda object, and the static
|
||||||
* the first argument in the invocation signature will correspond to the receiver.
|
* types of the captured arguments for the lambda.
|
||||||
* @param samMethod The primary method in the functional interface to which the lambda or method reference is
|
* In the event that the implementation method is an
|
||||||
* being converted, represented as a method handle.
|
* instance method, the first argument in the invocation
|
||||||
* @param implMethod The implementation method which should be called (with suitable adaptation of argument
|
* signature will correspond to the receiver.
|
||||||
* types, return types, and adjustment for captured arguments) when methods of the resulting
|
* @param samMethod The primary method in the functional interface to which
|
||||||
* functional interface instance are invoked.
|
* the lambda or method reference is being converted,
|
||||||
* @param instantiatedMethodType The signature of the primary functional interface method after type variables
|
* represented as a method handle.
|
||||||
* are substituted with their instantiation from the capture site
|
* @param implMethod The implementation method which should be called
|
||||||
* @return a CallSite, which, when invoked, will return an instance of the functional interface
|
* (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 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,
|
public static CallSite metaFactory(MethodHandles.Lookup caller,
|
||||||
String invokedName,
|
String invokedName,
|
||||||
@ -185,15 +204,17 @@ public class LambdaMetafactory {
|
|||||||
MethodType instantiatedMethodType)
|
MethodType instantiatedMethodType)
|
||||||
throws ReflectiveOperationException, LambdaConversionException {
|
throws ReflectiveOperationException, LambdaConversionException {
|
||||||
AbstractValidatingLambdaMetafactory mf;
|
AbstractValidatingLambdaMetafactory mf;
|
||||||
mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod, implMethod, instantiatedMethodType,
|
mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod,
|
||||||
0, EMPTY_CLASS_ARRAY);
|
implMethod, instantiatedMethodType,
|
||||||
|
false, EMPTY_CLASS_ARRAY, EMPTY_MT_ARRAY);
|
||||||
mf.validateMetafactoryArgs();
|
mf.validateMetafactoryArgs();
|
||||||
return mf.buildCallSite();
|
return mf.buildCallSite();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Alternate meta-factory for conversion of lambda expressions or method references to functional interfaces,
|
* Alternate meta-factory for conversion of lambda expressions or method
|
||||||
* which supports serialization and other uncommon options.
|
* references to functional interfaces, which supports serialization and
|
||||||
|
* other uncommon options.
|
||||||
*
|
*
|
||||||
* The declared argument list for this method is:
|
* The declared argument list for this method is:
|
||||||
*
|
*
|
||||||
@ -213,21 +234,28 @@ public class LambdaMetafactory {
|
|||||||
* int flags,
|
* int flags,
|
||||||
* int markerInterfaceCount, // IF flags has MARKERS set
|
* int markerInterfaceCount, // IF flags has MARKERS set
|
||||||
* Class... markerInterfaces // IF flags has MARKERS set
|
* Class... markerInterfaces // IF flags has MARKERS set
|
||||||
|
* int bridgeCount, // IF flags has BRIDGES set
|
||||||
|
* MethodType... bridges // IF flags has BRIDGES set
|
||||||
* )
|
* )
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges
|
* @param caller Stacked automatically by VM; represents a lookup context
|
||||||
* of the caller.
|
* 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 invokedName Stacked automatically by VM; the name of the invoked
|
||||||
* Currently unused.
|
* 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
|
* @param invokedType Stacked automatically by VM; the signature of the
|
||||||
* expected static type of the returned lambda object, and the static types of the captured
|
* invoked method, which includes the expected static
|
||||||
* arguments for the lambda. In the event that the implementation method is an instance method,
|
* type of the returned lambda object, and the static
|
||||||
* the first argument in the invocation signature will correspond to the receiver.
|
* types of the captured arguments for the lambda.
|
||||||
* @param args argument to pass, flags, marker interface count, and marker interfaces as described above
|
* In the event that the implementation method is an
|
||||||
* @return a CallSite, which, when invoked, will return an instance of the functional interface
|
* 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 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,
|
public static CallSite altMetaFactory(MethodHandles.Lookup caller,
|
||||||
String invokedName,
|
String invokedName,
|
||||||
@ -239,6 +267,7 @@ public class LambdaMetafactory {
|
|||||||
MethodType instantiatedMethodType = (MethodType)args[2];
|
MethodType instantiatedMethodType = (MethodType)args[2];
|
||||||
int flags = (Integer) args[3];
|
int flags = (Integer) args[3];
|
||||||
Class<?>[] markerInterfaces;
|
Class<?>[] markerInterfaces;
|
||||||
|
MethodType[] bridges;
|
||||||
int argIndex = 4;
|
int argIndex = 4;
|
||||||
if ((flags & FLAG_MARKERS) != 0) {
|
if ((flags & FLAG_MARKERS) != 0) {
|
||||||
int markerCount = (Integer) args[argIndex++];
|
int markerCount = (Integer) args[argIndex++];
|
||||||
@ -248,9 +277,30 @@ public class LambdaMetafactory {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
markerInterfaces = EMPTY_CLASS_ARRAY;
|
markerInterfaces = EMPTY_CLASS_ARRAY;
|
||||||
AbstractValidatingLambdaMetafactory mf;
|
if ((flags & FLAG_BRIDGES) != 0) {
|
||||||
mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod, implMethod, instantiatedMethodType,
|
int bridgeCount = (Integer) args[argIndex++];
|
||||||
flags, markerInterfaces);
|
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();
|
mf.validateMetafactoryArgs();
|
||||||
return mf.buildCallSite();
|
return mf.buildCallSite();
|
||||||
}
|
}
|
||||||
|
@ -27,10 +27,13 @@ package java.lang.invoke;
|
|||||||
|
|
||||||
import sun.invoke.util.Wrapper;
|
import sun.invoke.util.Wrapper;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.lang.ref.Reference;
|
||||||
import java.lang.ref.ReferenceQueue;
|
import java.lang.ref.ReferenceQueue;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import sun.invoke.util.BytecodeDescriptor;
|
import sun.invoke.util.BytecodeDescriptor;
|
||||||
import static java.lang.invoke.MethodHandleStatics.*;
|
import static java.lang.invoke.MethodHandleStatics.*;
|
||||||
import sun.invoke.util.VerifyType;
|
import sun.invoke.util.VerifyType;
|
||||||
@ -171,7 +174,7 @@ class MethodType implements java.io.Serializable {
|
|||||||
return new IndexOutOfBoundsException(num.toString());
|
return new IndexOutOfBoundsException(num.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
static final WeakInternSet internTable = new WeakInternSet();
|
static final ConcurrentWeakInternSet<MethodType> internTable = new ConcurrentWeakInternSet<>();
|
||||||
|
|
||||||
static final Class<?>[] NO_PTYPES = {};
|
static final Class<?>[] NO_PTYPES = {};
|
||||||
|
|
||||||
@ -1013,267 +1016,104 @@ s.writeObject(this.parameterArray());
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Weak intern set based on implementation of the <tt>HashSet</tt> and
|
* Simple implementation of weak concurrent intern set.
|
||||||
* <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.
|
|
||||||
*
|
*
|
||||||
* @see java.util.HashMap
|
* @param <T> interned type
|
||||||
* @see java.util.HashSet
|
|
||||||
* @see java.util.WeakHashMap
|
|
||||||
* @see java.lang.ref.WeakReference
|
|
||||||
*/
|
*/
|
||||||
private static class WeakInternSet {
|
private static class ConcurrentWeakInternSet<T> {
|
||||||
// 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
|
private final ConcurrentMap<WeakEntry<T>, WeakEntry<T>> map;
|
||||||
// by either of the constructors with arguments.
|
private final ReferenceQueue<T> stale;
|
||||||
// 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.
|
public ConcurrentWeakInternSet() {
|
||||||
private static final float DEFAULT_LOAD_FACTOR = 0.75f;
|
this.map = new ConcurrentHashMap<>();
|
||||||
|
this.stale = new ReferenceQueue<>();
|
||||||
// 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;
|
|
||||||
|
|
||||||
// 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];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new, empty <tt>WeakInternSet</tt> with the default initial
|
* Get the existing interned element.
|
||||||
* capacity (16) and load factor (0.75).
|
* This method returns null if no element is interned.
|
||||||
*/
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
* @param elem element to look up
|
||||||
* {@code entry} to a value {@code value} such that
|
* @return the interned element
|
||||||
* {@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) {
|
public T get(T elem) {
|
||||||
int h = hash(value.hashCode());
|
if (elem == null) throw new NullPointerException();
|
||||||
Entry[] tab = getTable();
|
expungeStaleElements();
|
||||||
int index = indexFor(h, tab.length);
|
|
||||||
Entry e = tab[index];
|
WeakEntry<T> value = map.get(new WeakEntry<>(elem));
|
||||||
MethodType g;
|
if (value != null) {
|
||||||
while (e != null) {
|
T res = value.get();
|
||||||
if (e.hash == h && eq(value, g = e.get()))
|
if (res != null) {
|
||||||
return g;
|
return res;
|
||||||
e = e.next;
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to add the specified value to the set and returns same value.
|
* Interns the element.
|
||||||
* If the set previously contained an entry for this value, the old
|
* Always returns non-null element, matching the one in the intern set.
|
||||||
* value is left untouched and returned as the result.
|
* 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
|
* @param elem element to add
|
||||||
* @return the previous entry associated with <tt>value</tt>, or
|
* @return element that was actually added
|
||||||
* <tt>value</tt> if there was no previous entry found
|
|
||||||
*/
|
*/
|
||||||
synchronized MethodType add(MethodType value) {
|
public T add(T elem) {
|
||||||
int h = hash(value.hashCode());
|
if (elem == null) throw new NullPointerException();
|
||||||
Entry[] tab = getTable();
|
|
||||||
int i = indexFor(h, tab.length);
|
// Playing double race here, and so spinloop is required.
|
||||||
MethodType g;
|
// First race is with two concurrent updaters.
|
||||||
for (Entry e = tab[i]; e != null; e = e.next) {
|
// Second race is with GC purging weak ref under our feet.
|
||||||
if (h == e.hash && eq(value, g = e.get())) {
|
// Hopefully, we almost always end up with a single pass.
|
||||||
return g;
|
T interned;
|
||||||
}
|
WeakEntry<T> e = new WeakEntry<>(elem, stale);
|
||||||
}
|
do {
|
||||||
Entry e = tab[i];
|
expungeStaleElements();
|
||||||
tab[i] = new Entry(value, queue, h, e);
|
WeakEntry<T> exist = map.putIfAbsent(e, e);
|
||||||
if (++size >= threshold)
|
interned = (exist == null) ? elem : exist.get();
|
||||||
resize(tab.length * 2);
|
} while (interned == null);
|
||||||
return value;
|
return interned;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void expungeStaleElements() {
|
||||||
* Rehashes the contents of this set into a new array with a
|
Reference<? extends T> reference;
|
||||||
* larger capacity. This method is called automatically when the
|
while ((reference = stale.poll()) != null) {
|
||||||
* number of keys in this set reaches its threshold.
|
map.remove(reference);
|
||||||
*
|
|
||||||
* 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 static class WeakEntry<T> extends WeakReference<T> {
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public final int hashcode;
|
||||||
* 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;
|
|
||||||
|
|
||||||
/**
|
public WeakEntry(T key, ReferenceQueue<T> queue) {
|
||||||
* Creates new entry.
|
|
||||||
*/
|
|
||||||
Entry(MethodType key,
|
|
||||||
ReferenceQueue<Object> queue,
|
|
||||||
int hash, Entry next) {
|
|
||||||
super(key, queue);
|
super(key, queue);
|
||||||
this.hash = hash;
|
hashcode = key.hashCode();
|
||||||
this.next = next;
|
}
|
||||||
}
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return hashcode;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -248,6 +248,7 @@ public abstract class Signature extends SignatureSpi {
|
|||||||
Signature sig;
|
Signature sig;
|
||||||
if (instance.impl instanceof Signature) {
|
if (instance.impl instanceof Signature) {
|
||||||
sig = (Signature)instance.impl;
|
sig = (Signature)instance.impl;
|
||||||
|
sig.algorithm = algorithm;
|
||||||
} else {
|
} else {
|
||||||
SignatureSpi spi = (SignatureSpi)instance.impl;
|
SignatureSpi spi = (SignatureSpi)instance.impl;
|
||||||
sig = new Delegate(spi, algorithm);
|
sig = new Delegate(spi, algorithm);
|
||||||
|
@ -40,6 +40,8 @@ import java.lang.reflect.Type;
|
|||||||
*/
|
*/
|
||||||
public class ClassRepository extends GenericDeclRepository<ClassSignature> {
|
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 superclass; // caches the generic superclass info
|
||||||
private Type[] superInterfaces; // caches the generic superinterface info
|
private Type[] superInterfaces; // caches the generic superinterface info
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ extern jboolean VerifyFixClassname(char *utf_name);
|
|||||||
static JNINativeMethod methods[] = {
|
static JNINativeMethod methods[] = {
|
||||||
{"getName0", "()" STR, (void *)&JVM_GetClassName},
|
{"getName0", "()" STR, (void *)&JVM_GetClassName},
|
||||||
{"getSuperclass", "()" CLS, NULL},
|
{"getSuperclass", "()" CLS, NULL},
|
||||||
{"getInterfaces", "()[" CLS, (void *)&JVM_GetClassInterfaces},
|
{"getInterfaces0", "()[" CLS, (void *)&JVM_GetClassInterfaces},
|
||||||
{"getClassLoader0", "()" JCL, (void *)&JVM_GetClassLoader},
|
{"getClassLoader0", "()" JCL, (void *)&JVM_GetClassLoader},
|
||||||
{"isInterface", "()Z", (void *)&JVM_IsInterface},
|
{"isInterface", "()Z", (void *)&JVM_IsInterface},
|
||||||
{"getSigners", "()[" OBJ, (void *)&JVM_GetClassSigners},
|
{"getSigners", "()[" OBJ, (void *)&JVM_GetClassSigners},
|
||||||
@ -70,7 +70,7 @@ static JNINativeMethod methods[] = {
|
|||||||
{"getProtectionDomain0", "()" PD, (void *)&JVM_GetProtectionDomain},
|
{"getProtectionDomain0", "()" PD, (void *)&JVM_GetProtectionDomain},
|
||||||
{"getDeclaredClasses0", "()[" CLS, (void *)&JVM_GetDeclaredClasses},
|
{"getDeclaredClasses0", "()[" CLS, (void *)&JVM_GetDeclaredClasses},
|
||||||
{"getDeclaringClass", "()" CLS, (void *)&JVM_GetDeclaringClass},
|
{"getDeclaringClass", "()" CLS, (void *)&JVM_GetDeclaringClass},
|
||||||
{"getGenericSignature", "()" STR, (void *)&JVM_GetClassSignature},
|
{"getGenericSignature0", "()" STR, (void *)&JVM_GetClassSignature},
|
||||||
{"getRawAnnotations", "()" BA, (void *)&JVM_GetClassAnnotations},
|
{"getRawAnnotations", "()" BA, (void *)&JVM_GetClassAnnotations},
|
||||||
{"getConstantPool", "()" CPL, (void *)&JVM_GetClassConstantPool},
|
{"getConstantPool", "()" CPL, (void *)&JVM_GetClassConstantPool},
|
||||||
{"desiredAssertionStatus0","("CLS")Z",(void *)&JVM_DesiredAssertionStatus},
|
{"desiredAssertionStatus0","("CLS")Z",(void *)&JVM_DesiredAssertionStatus},
|
||||||
|
112
jdk/test/java/security/Signature/SignatureGetAlgorithm.java
Normal file
112
jdk/test/java/security/Signature/SignatureGetAlgorithm.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user