mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8187443: Forest Consolidation: Move files to unified layout
Reviewed-by: darcy, ihse
This commit is contained in:
parent
270fe13182
commit
3789983e89
56923 changed files with 3 additions and 15727 deletions
|
@ -0,0 +1,548 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.lang.invoke;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.*;
|
||||
import sun.invoke.util.BytecodeDescriptor;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
import java.io.FilePermission;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.PropertyPermission;
|
||||
import java.util.Set;
|
||||
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
||||
|
||||
/**
|
||||
* Lambda metafactory implementation which dynamically creates an
|
||||
* inner-class-like class per lambda callsite.
|
||||
*
|
||||
* @see LambdaMetafactory
|
||||
*/
|
||||
/* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
|
||||
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
|
||||
|
||||
private static final int CLASSFILE_VERSION = 52;
|
||||
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 NAME_CTOR = "<init>";
|
||||
private static final String NAME_FACTORY = "get$Lambda";
|
||||
|
||||
//Serialization support
|
||||
private static final String NAME_SERIALIZED_LAMBDA = "java/lang/invoke/SerializedLambda";
|
||||
private static final String NAME_NOT_SERIALIZABLE_EXCEPTION = "java/io/NotSerializableException";
|
||||
private static final String DESCR_METHOD_WRITE_REPLACE = "()Ljava/lang/Object;";
|
||||
private static final String DESCR_METHOD_WRITE_OBJECT = "(Ljava/io/ObjectOutputStream;)V";
|
||||
private static final String DESCR_METHOD_READ_OBJECT = "(Ljava/io/ObjectInputStream;)V";
|
||||
private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace";
|
||||
private static final String NAME_METHOD_READ_OBJECT = "readObject";
|
||||
private static final String NAME_METHOD_WRITE_OBJECT = "writeObject";
|
||||
|
||||
private static final String DESCR_CLASS = "Ljava/lang/Class;";
|
||||
private static final String DESCR_STRING = "Ljava/lang/String;";
|
||||
private static final String DESCR_OBJECT = "Ljava/lang/Object;";
|
||||
private static final String DESCR_CTOR_SERIALIZED_LAMBDA
|
||||
= "(" + DESCR_CLASS + DESCR_STRING + DESCR_STRING + DESCR_STRING + "I"
|
||||
+ DESCR_STRING + DESCR_STRING + DESCR_STRING + DESCR_STRING + "[" + DESCR_OBJECT + ")V";
|
||||
|
||||
private static final String DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION = "(Ljava/lang/String;)V";
|
||||
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
|
||||
private static final AtomicInteger counter = new AtomicInteger(0);
|
||||
|
||||
// For dumping generated classes to disk, for debugging purposes
|
||||
private static final ProxyClassesDumper dumper;
|
||||
|
||||
static {
|
||||
final String key = "jdk.internal.lambda.dumpProxyClasses";
|
||||
String path = GetPropertyAction.privilegedGetProperty(key);
|
||||
dumper = (null == path) ? null : ProxyClassesDumper.getInstance(path);
|
||||
}
|
||||
|
||||
// See context values in AbstractValidatingLambdaMetafactory
|
||||
private final String implMethodClassName; // Name of type containing implementation "CC"
|
||||
private final String implMethodName; // Name of implementation method "impl"
|
||||
private final String implMethodDesc; // Type descriptor for implementation methods "(I)Ljava/lang/String;"
|
||||
private final MethodType constructorType; // Generated class constructor type "(CC)void"
|
||||
private final ClassWriter cw; // ASM class writer
|
||||
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"
|
||||
|
||||
/**
|
||||
* General meta-factory constructor, supporting both standard cases and
|
||||
* allowing for uncommon options such as serialization or bridging.
|
||||
*
|
||||
* @param caller Stacked automatically by VM; represents a lookup context
|
||||
* with the accessibility privileges of the caller.
|
||||
* @param invokedType Stacked automatically by VM; the signature of the
|
||||
* invoked method, which includes the expected static
|
||||
* type of the returned lambda object, and the static
|
||||
* types of the captured arguments for the lambda. In
|
||||
* the event that the implementation method is an
|
||||
* instance method, the first argument in the invocation
|
||||
* signature will correspond to the receiver.
|
||||
* @param samMethodName Name of the method in the functional interface to
|
||||
* which the lambda or method reference is being
|
||||
* converted, represented as a String.
|
||||
* @param samMethodType Type of the method in the functional interface to
|
||||
* which the lambda or method reference is being
|
||||
* converted, represented as a MethodType.
|
||||
* @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 LambdaConversionException If any of the meta-factory protocol
|
||||
* invariants are violated
|
||||
*/
|
||||
public InnerClassLambdaMetafactory(MethodHandles.Lookup caller,
|
||||
MethodType invokedType,
|
||||
String samMethodName,
|
||||
MethodType samMethodType,
|
||||
MethodHandle implMethod,
|
||||
MethodType instantiatedMethodType,
|
||||
boolean isSerializable,
|
||||
Class<?>[] markerInterfaces,
|
||||
MethodType[] additionalBridges)
|
||||
throws LambdaConversionException {
|
||||
super(caller, invokedType, samMethodName, samMethodType,
|
||||
implMethod, instantiatedMethodType,
|
||||
isSerializable, markerInterfaces, additionalBridges);
|
||||
implMethodClassName = implClass.getName().replace('.', '/');
|
||||
implMethodName = implInfo.getName();
|
||||
implMethodDesc = implInfo.getMethodType().toMethodDescriptorString();
|
||||
constructorType = invokedType.changeReturnType(Void.TYPE);
|
||||
lambdaClassName = targetClass.getName().replace('.', '/') + "$$Lambda$" + counter.incrementAndGet();
|
||||
cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
||||
int parameterCount = invokedType.parameterCount();
|
||||
if (parameterCount > 0) {
|
||||
argNames = new String[parameterCount];
|
||||
argDescs = new String[parameterCount];
|
||||
for (int i = 0; i < parameterCount; i++) {
|
||||
argNames[i] = "arg$" + (i + 1);
|
||||
argDescs[i] = BytecodeDescriptor.unparse(invokedType.parameterType(i));
|
||||
}
|
||||
} else {
|
||||
argNames = argDescs = EMPTY_STRING_ARRAY;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the CallSite. Generate a class file which implements the functional
|
||||
* interface, define the class, if there are no parameters create an instance
|
||||
* of the class which the CallSite will return, otherwise, generate handles
|
||||
* which will call the class' constructor.
|
||||
*
|
||||
* @return a CallSite, which, when invoked, will return an instance of the
|
||||
* functional interface
|
||||
* @throws ReflectiveOperationException
|
||||
* @throws LambdaConversionException If properly formed functional interface
|
||||
* is not found
|
||||
*/
|
||||
@Override
|
||||
CallSite buildCallSite() throws LambdaConversionException {
|
||||
final Class<?> innerClass = spinInnerClass();
|
||||
if (invokedType.parameterCount() == 0) {
|
||||
final Constructor<?>[] ctrs = AccessController.doPrivileged(
|
||||
new PrivilegedAction<>() {
|
||||
@Override
|
||||
public Constructor<?>[] run() {
|
||||
Constructor<?>[] ctrs = innerClass.getDeclaredConstructors();
|
||||
if (ctrs.length == 1) {
|
||||
// The lambda implementing inner class constructor is private, set
|
||||
// it accessible (by us) before creating the constant sole instance
|
||||
ctrs[0].setAccessible(true);
|
||||
}
|
||||
return ctrs;
|
||||
}
|
||||
});
|
||||
if (ctrs.length != 1) {
|
||||
throw new LambdaConversionException("Expected one lambda constructor for "
|
||||
+ innerClass.getCanonicalName() + ", got " + ctrs.length);
|
||||
}
|
||||
|
||||
try {
|
||||
Object inst = ctrs[0].newInstance();
|
||||
return new ConstantCallSite(MethodHandles.constant(samBase, inst));
|
||||
}
|
||||
catch (ReflectiveOperationException e) {
|
||||
throw new LambdaConversionException("Exception instantiating lambda object", e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
UNSAFE.ensureClassInitialized(innerClass);
|
||||
return new ConstantCallSite(
|
||||
MethodHandles.Lookup.IMPL_LOOKUP
|
||||
.findStatic(innerClass, NAME_FACTORY, invokedType));
|
||||
}
|
||||
catch (ReflectiveOperationException e) {
|
||||
throw new LambdaConversionException("Exception finding constructor", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a class file which implements the functional
|
||||
* interface, define and return the class.
|
||||
*
|
||||
* @implNote The class that is generated does not include signature
|
||||
* information for exceptions that may be present on the SAM method.
|
||||
* This is to reduce classfile size, and is harmless as checked exceptions
|
||||
* are erased anyway, no one will ever compile against this classfile,
|
||||
* and we make no guarantees about the reflective properties of lambda
|
||||
* objects.
|
||||
*
|
||||
* @return a Class which implements the functional interface
|
||||
* @throws LambdaConversionException If properly formed functional interface
|
||||
* is not found
|
||||
*/
|
||||
private Class<?> spinInnerClass() throws LambdaConversionException {
|
||||
String[] interfaces;
|
||||
String samIntf = samBase.getName().replace('.', '/');
|
||||
boolean accidentallySerializable = !isSerializable && Serializable.class.isAssignableFrom(samBase);
|
||||
if (markerInterfaces.length == 0) {
|
||||
interfaces = new String[]{samIntf};
|
||||
} else {
|
||||
// Assure no duplicate interfaces (ClassFormatError)
|
||||
Set<String> itfs = new LinkedHashSet<>(markerInterfaces.length + 1);
|
||||
itfs.add(samIntf);
|
||||
for (Class<?> markerInterface : markerInterfaces) {
|
||||
itfs.add(markerInterface.getName().replace('.', '/'));
|
||||
accidentallySerializable |= !isSerializable && Serializable.class.isAssignableFrom(markerInterface);
|
||||
}
|
||||
interfaces = itfs.toArray(new String[itfs.size()]);
|
||||
}
|
||||
|
||||
cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
|
||||
lambdaClassName, null,
|
||||
JAVA_LANG_OBJECT, interfaces);
|
||||
|
||||
// Generate final fields to be filled in by constructor
|
||||
for (int i = 0; i < argDescs.length; i++) {
|
||||
FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL,
|
||||
argNames[i],
|
||||
argDescs[i],
|
||||
null, null);
|
||||
fv.visitEnd();
|
||||
}
|
||||
|
||||
generateConstructor();
|
||||
|
||||
if (invokedType.parameterCount() != 0) {
|
||||
generateFactory();
|
||||
}
|
||||
|
||||
// Forward the SAM method
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName,
|
||||
samMethodType.toMethodDescriptorString(), null, null);
|
||||
mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
|
||||
new ForwardingMethodGenerator(mv).generate(samMethodType);
|
||||
|
||||
// Forward the bridges
|
||||
if (additionalBridges != null) {
|
||||
for (MethodType mt : additionalBridges) {
|
||||
mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samMethodName,
|
||||
mt.toMethodDescriptorString(), null, null);
|
||||
mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
|
||||
new ForwardingMethodGenerator(mv).generate(mt);
|
||||
}
|
||||
}
|
||||
|
||||
if (isSerializable)
|
||||
generateSerializationFriendlyMethods();
|
||||
else if (accidentallySerializable)
|
||||
generateSerializationHostileMethods();
|
||||
|
||||
cw.visitEnd();
|
||||
|
||||
// Define the generated class in this VM.
|
||||
|
||||
final byte[] classBytes = cw.toByteArray();
|
||||
|
||||
// If requested, dump out to a file for debugging purposes
|
||||
if (dumper != null) {
|
||||
AccessController.doPrivileged(new PrivilegedAction<>() {
|
||||
@Override
|
||||
public Void run() {
|
||||
dumper.dumpClass(lambdaClassName, classBytes);
|
||||
return null;
|
||||
}
|
||||
}, null,
|
||||
new FilePermission("<<ALL FILES>>", "read, write"),
|
||||
// createDirectories may need it
|
||||
new PropertyPermission("user.dir", "read"));
|
||||
}
|
||||
|
||||
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(), false);
|
||||
m.visitInsn(ARETURN);
|
||||
m.visitMaxs(-1, -1);
|
||||
m.visitEnd();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the constructor for the class
|
||||
*/
|
||||
private void generateConstructor() {
|
||||
// Generate constructor
|
||||
MethodVisitor ctor = cw.visitMethod(ACC_PRIVATE, NAME_CTOR,
|
||||
constructorType.toMethodDescriptorString(), null, null);
|
||||
ctor.visitCode();
|
||||
ctor.visitVarInsn(ALOAD, 0);
|
||||
ctor.visitMethodInsn(INVOKESPECIAL, JAVA_LANG_OBJECT, NAME_CTOR,
|
||||
METHOD_DESCRIPTOR_VOID, false);
|
||||
int parameterCount = invokedType.parameterCount();
|
||||
for (int i = 0, lvIndex = 0; i < parameterCount; i++) {
|
||||
ctor.visitVarInsn(ALOAD, 0);
|
||||
Class<?> argType = invokedType.parameterType(i);
|
||||
ctor.visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
|
||||
lvIndex += getParameterSize(argType);
|
||||
ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argDescs[i]);
|
||||
}
|
||||
ctor.visitInsn(RETURN);
|
||||
// Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
|
||||
ctor.visitMaxs(-1, -1);
|
||||
ctor.visitEnd();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a writeReplace method that supports serialization
|
||||
*/
|
||||
private void generateSerializationFriendlyMethods() {
|
||||
TypeConvertingMethodAdapter mv
|
||||
= new TypeConvertingMethodAdapter(
|
||||
cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
|
||||
NAME_METHOD_WRITE_REPLACE, DESCR_METHOD_WRITE_REPLACE,
|
||||
null, null));
|
||||
|
||||
mv.visitCode();
|
||||
mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA);
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitLdcInsn(Type.getType(targetClass));
|
||||
mv.visitLdcInsn(invokedType.returnType().getName().replace('.', '/'));
|
||||
mv.visitLdcInsn(samMethodName);
|
||||
mv.visitLdcInsn(samMethodType.toMethodDescriptorString());
|
||||
mv.visitLdcInsn(implInfo.getReferenceKind());
|
||||
mv.visitLdcInsn(implInfo.getDeclaringClass().getName().replace('.', '/'));
|
||||
mv.visitLdcInsn(implInfo.getName());
|
||||
mv.visitLdcInsn(implInfo.getMethodType().toMethodDescriptorString());
|
||||
mv.visitLdcInsn(instantiatedMethodType.toMethodDescriptorString());
|
||||
mv.iconst(argDescs.length);
|
||||
mv.visitTypeInsn(ANEWARRAY, JAVA_LANG_OBJECT);
|
||||
for (int i = 0; i < argDescs.length; i++) {
|
||||
mv.visitInsn(DUP);
|
||||
mv.iconst(i);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]);
|
||||
mv.boxIfTypePrimitive(Type.getType(argDescs[i]));
|
||||
mv.visitInsn(AASTORE);
|
||||
}
|
||||
mv.visitMethodInsn(INVOKESPECIAL, NAME_SERIALIZED_LAMBDA, NAME_CTOR,
|
||||
DESCR_CTOR_SERIALIZED_LAMBDA, false);
|
||||
mv.visitInsn(ARETURN);
|
||||
// Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
|
||||
mv.visitMaxs(-1, -1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a readObject/writeObject method that is hostile to serialization
|
||||
*/
|
||||
private void generateSerializationHostileMethods() {
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
|
||||
NAME_METHOD_WRITE_OBJECT, DESCR_METHOD_WRITE_OBJECT,
|
||||
null, SER_HOSTILE_EXCEPTIONS);
|
||||
mv.visitCode();
|
||||
mv.visitTypeInsn(NEW, NAME_NOT_SERIALIZABLE_EXCEPTION);
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitLdcInsn("Non-serializable lambda");
|
||||
mv.visitMethodInsn(INVOKESPECIAL, NAME_NOT_SERIALIZABLE_EXCEPTION, NAME_CTOR,
|
||||
DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION, false);
|
||||
mv.visitInsn(ATHROW);
|
||||
mv.visitMaxs(-1, -1);
|
||||
mv.visitEnd();
|
||||
|
||||
mv = cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
|
||||
NAME_METHOD_READ_OBJECT, DESCR_METHOD_READ_OBJECT,
|
||||
null, SER_HOSTILE_EXCEPTIONS);
|
||||
mv.visitCode();
|
||||
mv.visitTypeInsn(NEW, NAME_NOT_SERIALIZABLE_EXCEPTION);
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitLdcInsn("Non-serializable lambda");
|
||||
mv.visitMethodInsn(INVOKESPECIAL, NAME_NOT_SERIALIZABLE_EXCEPTION, NAME_CTOR,
|
||||
DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION, false);
|
||||
mv.visitInsn(ATHROW);
|
||||
mv.visitMaxs(-1, -1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
/**
|
||||
* This class generates a method body which calls the lambda implementation
|
||||
* method, converting arguments, as needed.
|
||||
*/
|
||||
private class ForwardingMethodGenerator extends TypeConvertingMethodAdapter {
|
||||
|
||||
ForwardingMethodGenerator(MethodVisitor mv) {
|
||||
super(mv);
|
||||
}
|
||||
|
||||
void generate(MethodType methodType) {
|
||||
visitCode();
|
||||
|
||||
if (implKind == MethodHandleInfo.REF_newInvokeSpecial) {
|
||||
visitTypeInsn(NEW, implMethodClassName);
|
||||
visitInsn(DUP);
|
||||
}
|
||||
for (int i = 0; i < argNames.length; i++) {
|
||||
visitVarInsn(ALOAD, 0);
|
||||
visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]);
|
||||
}
|
||||
|
||||
convertArgumentTypes(methodType);
|
||||
|
||||
// Invoke the method we want to forward to
|
||||
visitMethodInsn(invocationOpcode(), implMethodClassName,
|
||||
implMethodName, implMethodDesc,
|
||||
implClass.isInterface());
|
||||
|
||||
// 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
|
||||
Class<?> implReturnClass = implMethodType.returnType();
|
||||
Class<?> samReturnClass = methodType.returnType();
|
||||
convertType(implReturnClass, samReturnClass, samReturnClass);
|
||||
visitInsn(getReturnOpcode(samReturnClass));
|
||||
// Maxs computed by ClassWriter.COMPUTE_MAXS,these arguments ignored
|
||||
visitMaxs(-1, -1);
|
||||
visitEnd();
|
||||
}
|
||||
|
||||
private void convertArgumentTypes(MethodType samType) {
|
||||
int lvIndex = 0;
|
||||
int samParametersLength = samType.parameterCount();
|
||||
int captureArity = invokedType.parameterCount();
|
||||
for (int i = 0; i < samParametersLength; i++) {
|
||||
Class<?> argType = samType.parameterType(i);
|
||||
visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
|
||||
lvIndex += getParameterSize(argType);
|
||||
convertType(argType, implMethodType.parameterType(captureArity + i), instantiatedMethodType.parameterType(i));
|
||||
}
|
||||
}
|
||||
|
||||
private int invocationOpcode() throws InternalError {
|
||||
switch (implKind) {
|
||||
case MethodHandleInfo.REF_invokeStatic:
|
||||
return INVOKESTATIC;
|
||||
case MethodHandleInfo.REF_newInvokeSpecial:
|
||||
return INVOKESPECIAL;
|
||||
case MethodHandleInfo.REF_invokeVirtual:
|
||||
return INVOKEVIRTUAL;
|
||||
case MethodHandleInfo.REF_invokeInterface:
|
||||
return INVOKEINTERFACE;
|
||||
case MethodHandleInfo.REF_invokeSpecial:
|
||||
return INVOKESPECIAL;
|
||||
default:
|
||||
throw new InternalError("Unexpected invocation kind: " + implKind);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue