8024637: Lambda linkage performance - use reflection instead of ASM to manipulate parameter types
8023984: Lambda linkage performance - use a method ref to a static factory instead of a ctor ref Reviewed-by: briangoetz, rfield
This commit is contained in:
parent
21a239f4c5
commit
7055290bbe
@ -26,6 +26,7 @@
|
|||||||
package java.lang.invoke;
|
package java.lang.invoke;
|
||||||
|
|
||||||
import jdk.internal.org.objectweb.asm.*;
|
import jdk.internal.org.objectweb.asm.*;
|
||||||
|
import sun.invoke.util.BytecodeDescriptor;
|
||||||
import sun.misc.Unsafe;
|
import sun.misc.Unsafe;
|
||||||
import sun.security.action.GetPropertyAction;
|
import sun.security.action.GetPropertyAction;
|
||||||
|
|
||||||
@ -54,6 +55,7 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
|||||||
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 JAVA_LANG_OBJECT = "java/lang/Object";
|
private static final String JAVA_LANG_OBJECT = "java/lang/Object";
|
||||||
private static final String NAME_CTOR = "<init>";
|
private static final String NAME_CTOR = "<init>";
|
||||||
|
private static final String NAME_FACTORY = "get$Lambda";
|
||||||
|
|
||||||
//Serialization support
|
//Serialization support
|
||||||
private static final String NAME_SERIALIZED_LAMBDA = "java/lang/invoke/SerializedLambda";
|
private static final String NAME_SERIALIZED_LAMBDA = "java/lang/invoke/SerializedLambda";
|
||||||
@ -76,6 +78,8 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
|||||||
private static final String[] SER_HOSTILE_EXCEPTIONS = new String[] {NAME_NOT_SERIALIZABLE_EXCEPTION};
|
private static final String[] SER_HOSTILE_EXCEPTIONS = new String[] {NAME_NOT_SERIALIZABLE_EXCEPTION};
|
||||||
|
|
||||||
|
|
||||||
|
private static final String[] EMPTY_STRING_ARRAY = new String[0];
|
||||||
|
|
||||||
// Used to ensure that each spun class name is unique
|
// Used to ensure that each spun class name is unique
|
||||||
private static final AtomicInteger counter = new AtomicInteger(0);
|
private static final AtomicInteger counter = new AtomicInteger(0);
|
||||||
|
|
||||||
@ -94,15 +98,12 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
|||||||
private final String implMethodClassName; // Name of type containing implementation "CC"
|
private final String implMethodClassName; // Name of type containing implementation "CC"
|
||||||
private final String implMethodName; // Name of implementation method "impl"
|
private final String implMethodName; // Name of implementation method "impl"
|
||||||
private final String implMethodDesc; // Type descriptor for implementation methods "(I)Ljava/lang/String;"
|
private final String implMethodDesc; // Type descriptor for implementation methods "(I)Ljava/lang/String;"
|
||||||
private final Type[] implMethodArgumentTypes; // ASM types for implementation method parameters
|
private final Class<?> implMethodReturnClass; // class for implementaion method return type "Ljava/lang/String;"
|
||||||
private final Type implMethodReturnType; // ASM type for implementation method return type "Ljava/lang/String;"
|
|
||||||
private final MethodType constructorType; // Generated class constructor type "(CC)void"
|
private final MethodType constructorType; // Generated class constructor type "(CC)void"
|
||||||
private final String constructorDesc; // Type descriptor for constructor "(LCC;)V"
|
|
||||||
private final ClassWriter cw; // ASM class writer
|
private final ClassWriter cw; // ASM class writer
|
||||||
private final Type[] argTypes; // ASM types for the constructor arguments
|
|
||||||
private final String[] argNames; // Generated names for the constructor arguments
|
private final String[] argNames; // Generated names for the constructor arguments
|
||||||
|
private final String[] argDescs; // Type descriptors for the constructor arguments
|
||||||
private final String lambdaClassName; // Generated name for the generated class "X$$Lambda$1"
|
private final String lambdaClassName; // Generated name for the generated class "X$$Lambda$1"
|
||||||
private final Type[] instantiatedArgumentTypes; // ASM types for the functional interface arguments
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* General meta-factory constructor, supporting both standard cases and
|
* General meta-factory constructor, supporting both standard cases and
|
||||||
@ -157,22 +158,23 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
|||||||
implMethodClassName = implDefiningClass.getName().replace('.', '/');
|
implMethodClassName = implDefiningClass.getName().replace('.', '/');
|
||||||
implMethodName = implInfo.getName();
|
implMethodName = implInfo.getName();
|
||||||
implMethodDesc = implMethodType.toMethodDescriptorString();
|
implMethodDesc = implMethodType.toMethodDescriptorString();
|
||||||
Type implMethodAsmType = Type.getMethodType(implMethodDesc);
|
implMethodReturnClass = (implKind == MethodHandleInfo.REF_newInvokeSpecial)
|
||||||
implMethodArgumentTypes = implMethodAsmType.getArgumentTypes();
|
? implDefiningClass
|
||||||
implMethodReturnType = (implKind == MethodHandleInfo.REF_newInvokeSpecial)
|
: implMethodType.returnType();
|
||||||
? Type.getObjectType(implMethodClassName)
|
|
||||||
: implMethodAsmType.getReturnType();
|
|
||||||
constructorType = invokedType.changeReturnType(Void.TYPE);
|
constructorType = invokedType.changeReturnType(Void.TYPE);
|
||||||
constructorDesc = constructorType.toMethodDescriptorString();
|
|
||||||
lambdaClassName = targetClass.getName().replace('.', '/') + "$$Lambda$" + counter.incrementAndGet();
|
lambdaClassName = targetClass.getName().replace('.', '/') + "$$Lambda$" + counter.incrementAndGet();
|
||||||
cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
||||||
argTypes = Type.getArgumentTypes(constructorDesc);
|
int parameterCount = invokedType.parameterCount();
|
||||||
argNames = new String[argTypes.length];
|
if (parameterCount > 0) {
|
||||||
for (int i = 0; i < argTypes.length; i++) {
|
argNames = new String[parameterCount];
|
||||||
|
argDescs = new String[parameterCount];
|
||||||
|
for (int i = 0; i < parameterCount; i++) {
|
||||||
argNames[i] = "arg$" + (i + 1);
|
argNames[i] = "arg$" + (i + 1);
|
||||||
|
argDescs[i] = BytecodeDescriptor.unparse(invokedType.parameterType(i));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
argNames = argDescs = EMPTY_STRING_ARRAY;
|
||||||
}
|
}
|
||||||
instantiatedArgumentTypes = Type.getArgumentTypes(
|
|
||||||
instantiatedMethodType.toMethodDescriptorString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -222,8 +224,7 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
|||||||
try {
|
try {
|
||||||
return new ConstantCallSite(
|
return new ConstantCallSite(
|
||||||
MethodHandles.Lookup.IMPL_LOOKUP
|
MethodHandles.Lookup.IMPL_LOOKUP
|
||||||
.findConstructor(innerClass, constructorType)
|
.findStatic(innerClass, NAME_FACTORY, invokedType));
|
||||||
.asType(constructorType.changeReturnType(samBase)));
|
|
||||||
}
|
}
|
||||||
catch (ReflectiveOperationException e) {
|
catch (ReflectiveOperationException e) {
|
||||||
throw new LambdaConversionException("Exception finding constructor", e);
|
throw new LambdaConversionException("Exception finding constructor", e);
|
||||||
@ -268,29 +269,31 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
|||||||
JAVA_LANG_OBJECT, interfaces);
|
JAVA_LANG_OBJECT, interfaces);
|
||||||
|
|
||||||
// Generate final fields to be filled in by constructor
|
// Generate final fields to be filled in by constructor
|
||||||
for (int i = 0; i < argTypes.length; i++) {
|
for (int i = 0; i < argDescs.length; i++) {
|
||||||
FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL,
|
FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL,
|
||||||
argNames[i],
|
argNames[i],
|
||||||
argTypes[i].getDescriptor(),
|
argDescs[i],
|
||||||
null, null);
|
null, null);
|
||||||
fv.visitEnd();
|
fv.visitEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
generateConstructor();
|
generateConstructor();
|
||||||
|
|
||||||
|
if (invokedType.parameterCount() != 0) {
|
||||||
|
generateFactory();
|
||||||
|
}
|
||||||
|
|
||||||
// Forward the SAM method
|
// Forward the SAM method
|
||||||
String methodDescriptor = samMethodType.toMethodDescriptorString();
|
|
||||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName,
|
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName,
|
||||||
methodDescriptor, null, null);
|
samMethodType.toMethodDescriptorString(), null, null);
|
||||||
new ForwardingMethodGenerator(mv).generate(methodDescriptor);
|
new ForwardingMethodGenerator(mv).generate(samMethodType);
|
||||||
|
|
||||||
// Forward the bridges
|
// Forward the bridges
|
||||||
if (additionalBridges != null) {
|
if (additionalBridges != null) {
|
||||||
for (MethodType mt : additionalBridges) {
|
for (MethodType mt : additionalBridges) {
|
||||||
methodDescriptor = mt.toMethodDescriptorString();
|
|
||||||
mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samMethodName,
|
mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samMethodName,
|
||||||
methodDescriptor, null, null);
|
mt.toMethodDescriptorString(), null, null);
|
||||||
new ForwardingMethodGenerator(mv).generate(methodDescriptor);
|
new ForwardingMethodGenerator(mv).generate(mt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,24 +325,44 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
|||||||
return UNSAFE.defineAnonymousClass(targetClass, classBytes, null);
|
return UNSAFE.defineAnonymousClass(targetClass, classBytes, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the factory method for the class
|
||||||
|
*/
|
||||||
|
private void generateFactory() {
|
||||||
|
MethodVisitor m = cw.visitMethod(ACC_PRIVATE | ACC_STATIC, NAME_FACTORY, invokedType.toMethodDescriptorString(), null, null);
|
||||||
|
m.visitCode();
|
||||||
|
m.visitTypeInsn(NEW, lambdaClassName);
|
||||||
|
m.visitInsn(Opcodes.DUP);
|
||||||
|
int parameterCount = invokedType.parameterCount();
|
||||||
|
for (int typeIndex = 0, varIndex = 0; typeIndex < parameterCount; typeIndex++) {
|
||||||
|
Class<?> argType = invokedType.parameterType(typeIndex);
|
||||||
|
m.visitVarInsn(getLoadOpcode(argType), varIndex);
|
||||||
|
varIndex += getParameterSize(argType);
|
||||||
|
}
|
||||||
|
m.visitMethodInsn(INVOKESPECIAL, lambdaClassName, NAME_CTOR, constructorType.toMethodDescriptorString());
|
||||||
|
m.visitInsn(ARETURN);
|
||||||
|
m.visitMaxs(-1, -1);
|
||||||
|
m.visitEnd();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate the constructor for the class
|
* Generate the constructor for the class
|
||||||
*/
|
*/
|
||||||
private void generateConstructor() {
|
private void generateConstructor() {
|
||||||
// Generate constructor
|
// Generate constructor
|
||||||
MethodVisitor ctor = cw.visitMethod(ACC_PRIVATE, NAME_CTOR,
|
MethodVisitor ctor = cw.visitMethod(ACC_PRIVATE, NAME_CTOR,
|
||||||
constructorDesc, null, null);
|
constructorType.toMethodDescriptorString(), null, null);
|
||||||
ctor.visitCode();
|
ctor.visitCode();
|
||||||
ctor.visitVarInsn(ALOAD, 0);
|
ctor.visitVarInsn(ALOAD, 0);
|
||||||
ctor.visitMethodInsn(INVOKESPECIAL, JAVA_LANG_OBJECT, NAME_CTOR,
|
ctor.visitMethodInsn(INVOKESPECIAL, JAVA_LANG_OBJECT, NAME_CTOR,
|
||||||
METHOD_DESCRIPTOR_VOID);
|
METHOD_DESCRIPTOR_VOID);
|
||||||
int lvIndex = 0;
|
int parameterCount = invokedType.parameterCount();
|
||||||
for (int i = 0; i < argTypes.length; i++) {
|
for (int i = 0, lvIndex = 0; i < parameterCount; i++) {
|
||||||
ctor.visitVarInsn(ALOAD, 0);
|
ctor.visitVarInsn(ALOAD, 0);
|
||||||
ctor.visitVarInsn(argTypes[i].getOpcode(ILOAD), lvIndex + 1);
|
Class<?> argType = invokedType.parameterType(i);
|
||||||
lvIndex += argTypes[i].getSize();
|
ctor.visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
|
||||||
ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i],
|
lvIndex += getParameterSize(argType);
|
||||||
argTypes[i].getDescriptor());
|
ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argDescs[i]);
|
||||||
}
|
}
|
||||||
ctor.visitInsn(RETURN);
|
ctor.visitInsn(RETURN);
|
||||||
// Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
|
// Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
|
||||||
@ -369,16 +392,14 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
|||||||
mv.visitLdcInsn(implInfo.getName());
|
mv.visitLdcInsn(implInfo.getName());
|
||||||
mv.visitLdcInsn(implInfo.getMethodType().toMethodDescriptorString());
|
mv.visitLdcInsn(implInfo.getMethodType().toMethodDescriptorString());
|
||||||
mv.visitLdcInsn(instantiatedMethodType.toMethodDescriptorString());
|
mv.visitLdcInsn(instantiatedMethodType.toMethodDescriptorString());
|
||||||
|
mv.iconst(argDescs.length);
|
||||||
mv.iconst(argTypes.length);
|
|
||||||
mv.visitTypeInsn(ANEWARRAY, JAVA_LANG_OBJECT);
|
mv.visitTypeInsn(ANEWARRAY, JAVA_LANG_OBJECT);
|
||||||
for (int i = 0; i < argTypes.length; i++) {
|
for (int i = 0; i < argDescs.length; i++) {
|
||||||
mv.visitInsn(DUP);
|
mv.visitInsn(DUP);
|
||||||
mv.iconst(i);
|
mv.iconst(i);
|
||||||
mv.visitVarInsn(ALOAD, 0);
|
mv.visitVarInsn(ALOAD, 0);
|
||||||
mv.visitFieldInsn(GETFIELD, lambdaClassName, argNames[i],
|
mv.visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]);
|
||||||
argTypes[i].getDescriptor());
|
mv.boxIfTypePrimitive(Type.getType(argDescs[i]));
|
||||||
mv.boxIfTypePrimitive(argTypes[i]);
|
|
||||||
mv.visitInsn(AASTORE);
|
mv.visitInsn(AASTORE);
|
||||||
}
|
}
|
||||||
mv.visitMethodInsn(INVOKESPECIAL, NAME_SERIALIZED_LAMBDA, NAME_CTOR,
|
mv.visitMethodInsn(INVOKESPECIAL, NAME_SERIALIZED_LAMBDA, NAME_CTOR,
|
||||||
@ -430,20 +451,19 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
|||||||
super(mv);
|
super(mv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate(String methodDescriptor) {
|
void generate(MethodType methodType) {
|
||||||
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 < argNames.length; i++) {
|
||||||
visitVarInsn(ALOAD, 0);
|
visitVarInsn(ALOAD, 0);
|
||||||
visitFieldInsn(GETFIELD, lambdaClassName, argNames[i],
|
visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]);
|
||||||
argTypes[i].getDescriptor());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
convertArgumentTypes(Type.getArgumentTypes(methodDescriptor));
|
convertArgumentTypes(methodType);
|
||||||
|
|
||||||
// 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);
|
||||||
@ -451,46 +471,36 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
|||||||
// 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'
|
// Note: if adapting from non-void to void, the 'return'
|
||||||
// instruction will pop the unneeded result
|
// instruction will pop the unneeded result
|
||||||
Type samReturnType = Type.getReturnType(methodDescriptor);
|
Class<?> samReturnClass = methodType.returnType();
|
||||||
convertType(implMethodReturnType, samReturnType, samReturnType);
|
convertType(implMethodReturnClass, samReturnClass, samReturnClass);
|
||||||
visitInsn(samReturnType.getOpcode(Opcodes.IRETURN));
|
visitInsn(getReturnOpcode(samReturnClass));
|
||||||
// Maxs computed by ClassWriter.COMPUTE_MAXS,these arguments ignored
|
// Maxs computed by ClassWriter.COMPUTE_MAXS,these arguments ignored
|
||||||
visitMaxs(-1, -1);
|
visitMaxs(-1, -1);
|
||||||
visitEnd();
|
visitEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void convertArgumentTypes(Type[] samArgumentTypes) {
|
private void convertArgumentTypes(MethodType samType) {
|
||||||
int lvIndex = 0;
|
int lvIndex = 0;
|
||||||
boolean samIncludesReceiver = implIsInstanceMethod &&
|
boolean samIncludesReceiver = implIsInstanceMethod &&
|
||||||
argTypes.length == 0;
|
invokedType.parameterCount() == 0;
|
||||||
int samReceiverLength = samIncludesReceiver ? 1 : 0;
|
int samReceiverLength = samIncludesReceiver ? 1 : 0;
|
||||||
if (samIncludesReceiver) {
|
if (samIncludesReceiver) {
|
||||||
// push receiver
|
// push receiver
|
||||||
Type rcvrType = samArgumentTypes[0];
|
Class<?> rcvrType = samType.parameterType(0);
|
||||||
Type instantiatedRcvrType = instantiatedArgumentTypes[0];
|
visitVarInsn(getLoadOpcode(rcvrType), lvIndex + 1);
|
||||||
|
lvIndex += getParameterSize(rcvrType);
|
||||||
visitVarInsn(rcvrType.getOpcode(ILOAD), lvIndex + 1);
|
convertType(rcvrType, implDefiningClass, instantiatedMethodType.parameterType(0));
|
||||||
lvIndex += rcvrType.getSize();
|
|
||||||
convertType(rcvrType, Type.getType(implDefiningClass), instantiatedRcvrType);
|
|
||||||
}
|
}
|
||||||
int argOffset = implMethodArgumentTypes.length - samArgumentTypes.length;
|
int samParametersLength = samType.parameterCount();
|
||||||
for (int i = samReceiverLength; i < samArgumentTypes.length; i++) {
|
int argOffset = implMethodType.parameterCount() - samParametersLength;
|
||||||
Type argType = samArgumentTypes[i];
|
for (int i = samReceiverLength; i < samParametersLength; i++) {
|
||||||
Type targetType = implMethodArgumentTypes[argOffset + i];
|
Class<?> argType = samType.parameterType(i);
|
||||||
Type instantiatedArgType = instantiatedArgumentTypes[i];
|
visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
|
||||||
|
lvIndex += getParameterSize(argType);
|
||||||
visitVarInsn(argType.getOpcode(ILOAD), lvIndex + 1);
|
convertType(argType, implMethodType.parameterType(argOffset + i), instantiatedMethodType.parameterType(i));
|
||||||
lvIndex += argType.getSize();
|
|
||||||
convertType(argType, targetType, instantiatedArgType);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void convertType(Type argType, Type targetType, Type functionalType) {
|
|
||||||
convertType(argType.getDescriptor(),
|
|
||||||
targetType.getDescriptor(),
|
|
||||||
functionalType.getDescriptor());
|
|
||||||
}
|
|
||||||
|
|
||||||
private int invocationOpcode() throws InternalError {
|
private int invocationOpcode() throws InternalError {
|
||||||
switch (implKind) {
|
switch (implKind) {
|
||||||
case MethodHandleInfo.REF_invokeStatic:
|
case MethodHandleInfo.REF_invokeStatic:
|
||||||
@ -508,4 +518,43 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int getParameterSize(Class<?> c) {
|
||||||
|
if (c == Void.TYPE) {
|
||||||
|
return 0;
|
||||||
|
} else if (c == Long.TYPE || c == Double.TYPE) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getLoadOpcode(Class<?> c) {
|
||||||
|
if(c == Void.TYPE) {
|
||||||
|
throw new InternalError("Unexpected void type of load opcode");
|
||||||
|
}
|
||||||
|
return ILOAD + getOpcodeOffset(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getReturnOpcode(Class<?> c) {
|
||||||
|
if(c == Void.TYPE) {
|
||||||
|
return RETURN;
|
||||||
|
}
|
||||||
|
return IRETURN + getOpcodeOffset(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getOpcodeOffset(Class<?> c) {
|
||||||
|
if (c.isPrimitive()) {
|
||||||
|
if (c == Long.TYPE) {
|
||||||
|
return 1;
|
||||||
|
} else if (c == Float.TYPE) {
|
||||||
|
return 2;
|
||||||
|
} else if (c == Double.TYPE) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ package java.lang.invoke;
|
|||||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||||
import jdk.internal.org.objectweb.asm.Type;
|
import jdk.internal.org.objectweb.asm.Type;
|
||||||
|
import sun.invoke.util.BytecodeDescriptor;
|
||||||
import sun.invoke.util.Wrapper;
|
import sun.invoke.util.Wrapper;
|
||||||
import static sun.invoke.util.Wrapper.*;
|
import static sun.invoke.util.Wrapper.*;
|
||||||
|
|
||||||
@ -204,27 +205,27 @@ class TypeConvertingMethodAdapter extends MethodVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert an argument of type 'argType' to be passed to 'targetType' assuring that it is 'functionalType'.
|
* Convert an argument of type 'arg' to be passed to 'target' assuring that it is 'functional'.
|
||||||
* Insert the needed conversion instructions in the method code.
|
* Insert the needed conversion instructions in the method code.
|
||||||
* @param argType
|
* @param arg
|
||||||
* @param targetType
|
* @param target
|
||||||
* @param functionalType
|
* @param functional
|
||||||
*/
|
*/
|
||||||
void convertType(String dArg, String dTarget, String dFunctional) {
|
void convertType(Class<?> arg, Class<?> target, Class<?> functional) {
|
||||||
if (dArg.equals(dTarget)) {
|
if (arg.equals(target)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Wrapper wArg = toWrapper(dArg);
|
if (arg == Void.TYPE || target == Void.TYPE) {
|
||||||
Wrapper wTarget = toWrapper(dTarget);
|
|
||||||
if (wArg == VOID || wTarget == VOID) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isPrimitive(wArg)) {
|
if (arg.isPrimitive()) {
|
||||||
if (isPrimitive(wTarget)) {
|
Wrapper wArg = Wrapper.forPrimitiveType(arg);
|
||||||
|
if (target.isPrimitive()) {
|
||||||
// Both primitives: widening
|
// Both primitives: widening
|
||||||
widen(wArg, wTarget);
|
widen(wArg, Wrapper.forPrimitiveType(target));
|
||||||
} else {
|
} else {
|
||||||
// Primitive argument to reference target
|
// Primitive argument to reference target
|
||||||
|
String dTarget = BytecodeDescriptor.unparse(target);
|
||||||
Wrapper wPrimTarget = wrapperOrNullFromDescriptor(dTarget);
|
Wrapper wPrimTarget = wrapperOrNullFromDescriptor(dTarget);
|
||||||
if (wPrimTarget != null) {
|
if (wPrimTarget != null) {
|
||||||
// The target is a boxed primitive type, widen to get there before boxing
|
// The target is a boxed primitive type, widen to get there before boxing
|
||||||
@ -237,16 +238,18 @@ class TypeConvertingMethodAdapter extends MethodVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
String dArg = BytecodeDescriptor.unparse(arg);
|
||||||
String dSrc;
|
String dSrc;
|
||||||
Wrapper wFunctional = toWrapper(dFunctional);
|
if (functional.isPrimitive()) {
|
||||||
if (isPrimitive(wFunctional)) {
|
|
||||||
dSrc = dArg;
|
dSrc = dArg;
|
||||||
} else {
|
} else {
|
||||||
// Cast to convert to possibly more specific type, and generate CCE for invalid arg
|
// Cast to convert to possibly more specific type, and generate CCE for invalid arg
|
||||||
dSrc = dFunctional;
|
dSrc = BytecodeDescriptor.unparse(functional);
|
||||||
cast(dArg, dFunctional);
|
cast(dArg, dSrc);
|
||||||
}
|
}
|
||||||
if (isPrimitive(wTarget)) {
|
String dTarget = BytecodeDescriptor.unparse(target);
|
||||||
|
if (target.isPrimitive()) {
|
||||||
|
Wrapper wTarget = toWrapper(dTarget);
|
||||||
// Reference argument to primitive target
|
// Reference argument to primitive target
|
||||||
Wrapper wps = wrapperOrNullFromDescriptor(dSrc);
|
Wrapper wps = wrapperOrNullFromDescriptor(dSrc);
|
||||||
if (wps != null) {
|
if (wps != null) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user