2012-10-25 17:34:24 -07:00
|
|
|
/*
|
2021-06-02 11:57:31 +00:00
|
|
|
* Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
|
2012-10-25 17:34:24 -07:00
|
|
|
* 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;
|
|
|
|
|
2020-10-19 18:27:50 +00:00
|
|
|
import jdk.internal.misc.CDS;
|
2013-06-19 11:47:14 +01:00
|
|
|
import jdk.internal.org.objectweb.asm.*;
|
2013-10-31 10:37:08 -04:00
|
|
|
import sun.invoke.util.BytecodeDescriptor;
|
2020-10-29 21:11:37 +00:00
|
|
|
import sun.invoke.util.VerifyAccess;
|
2013-10-09 09:41:40 -07:00
|
|
|
import sun.security.action.GetPropertyAction;
|
2019-10-28 15:03:36 +01:00
|
|
|
import sun.security.action.GetBooleanAction;
|
2013-07-11 14:02:20 +01:00
|
|
|
|
2013-10-09 09:41:40 -07:00
|
|
|
import java.io.FilePermission;
|
2013-10-29 12:31:27 -04:00
|
|
|
import java.io.Serializable;
|
2020-12-01 00:24:40 +00:00
|
|
|
import java.lang.constant.ConstantDescs;
|
8238358: Implementation of JEP 371: Hidden Classes
Co-authored-by: Lois Foltan <lois.foltan@oracle.com>
Co-authored-by: David Holmes <david.holmes@oracle.com>
Co-authored-by: Harold Seigel <harold.seigel@oracle.com>
Co-authored-by: Serguei Spitsyn <serguei.spitsyn@oracle.com>
Co-authored-by: Alex Buckley <alex.buckley@oracle.com>
Co-authored-by: Jamsheed Mohammed C M <jamsheed.c.m@oracle.com>
Co-authored-by: Jan Lahoda <jan.lahoda@oracle.com>
Co-authored-by: Amy Lu <amy.lu@oracle.com>
Reviewed-by: alanb, cjplummer, coleenp, dholmes, dlong, forax, jlahoda, psandoz, plevart, sspitsyn, vromero
2020-04-21 06:55:38 -07:00
|
|
|
import java.lang.invoke.MethodHandles.Lookup;
|
|
|
|
import java.lang.reflect.Modifier;
|
2013-06-19 11:47:14 +01:00
|
|
|
import java.security.AccessController;
|
|
|
|
import java.security.PrivilegedAction;
|
2013-10-23 15:16:35 -07:00
|
|
|
import java.util.LinkedHashSet;
|
2013-07-11 14:02:20 +01:00
|
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
2013-10-09 09:41:40 -07:00
|
|
|
import java.util.PropertyPermission;
|
2013-10-23 15:16:35 -07:00
|
|
|
import java.util.Set;
|
2013-07-11 14:02:20 +01:00
|
|
|
|
2021-10-28 18:32:50 +00:00
|
|
|
import static java.lang.invoke.MethodHandleStatics.CLASSFILE_VERSION;
|
8238358: Implementation of JEP 371: Hidden Classes
Co-authored-by: Lois Foltan <lois.foltan@oracle.com>
Co-authored-by: David Holmes <david.holmes@oracle.com>
Co-authored-by: Harold Seigel <harold.seigel@oracle.com>
Co-authored-by: Serguei Spitsyn <serguei.spitsyn@oracle.com>
Co-authored-by: Alex Buckley <alex.buckley@oracle.com>
Co-authored-by: Jamsheed Mohammed C M <jamsheed.c.m@oracle.com>
Co-authored-by: Jan Lahoda <jan.lahoda@oracle.com>
Co-authored-by: Amy Lu <amy.lu@oracle.com>
Reviewed-by: alanb, cjplummer, coleenp, dholmes, dlong, forax, jlahoda, psandoz, plevart, sspitsyn, vromero
2020-04-21 06:55:38 -07:00
|
|
|
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
|
|
|
|
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG;
|
2021-10-28 18:32:50 +00:00
|
|
|
import static java.lang.invoke.MethodType.methodType;
|
2013-07-11 14:02:20 +01:00
|
|
|
import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
2012-10-25 17:34:24 -07:00
|
|
|
|
|
|
|
/**
|
2013-07-11 14:02:20 +01:00
|
|
|
* Lambda metafactory implementation which dynamically creates an
|
|
|
|
* inner-class-like class per lambda callsite.
|
2013-02-16 12:36:54 -08:00
|
|
|
*
|
|
|
|
* @see LambdaMetafactory
|
2012-10-25 17:34:24 -07:00
|
|
|
*/
|
2013-02-16 12:36:54 -08:00
|
|
|
/* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
|
2012-10-25 17:34:24 -07:00
|
|
|
private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
|
2013-10-20 18:07:40 -07:00
|
|
|
private static final String JAVA_LANG_OBJECT = "java/lang/Object";
|
2012-10-25 17:34:24 -07:00
|
|
|
private static final String NAME_CTOR = "<init>";
|
2020-09-25 10:10:36 +00:00
|
|
|
private static final String LAMBDA_INSTANCE_FIELD = "LAMBDA_INSTANCE$";
|
2012-10-25 17:34:24 -07:00
|
|
|
|
|
|
|
//Serialization support
|
2013-02-16 12:36:54 -08:00
|
|
|
private static final String NAME_SERIALIZED_LAMBDA = "java/lang/invoke/SerializedLambda";
|
2013-10-29 12:31:27 -04:00
|
|
|
private static final String NAME_NOT_SERIALIZABLE_EXCEPTION = "java/io/NotSerializableException";
|
2012-10-25 17:34:24 -07:00
|
|
|
private static final String DESCR_METHOD_WRITE_REPLACE = "()Ljava/lang/Object;";
|
2013-10-29 12:31:27 -04:00
|
|
|
private static final String DESCR_METHOD_WRITE_OBJECT = "(Ljava/io/ObjectOutputStream;)V";
|
|
|
|
private static final String DESCR_METHOD_READ_OBJECT = "(Ljava/io/ObjectInputStream;)V";
|
8238358: Implementation of JEP 371: Hidden Classes
Co-authored-by: Lois Foltan <lois.foltan@oracle.com>
Co-authored-by: David Holmes <david.holmes@oracle.com>
Co-authored-by: Harold Seigel <harold.seigel@oracle.com>
Co-authored-by: Serguei Spitsyn <serguei.spitsyn@oracle.com>
Co-authored-by: Alex Buckley <alex.buckley@oracle.com>
Co-authored-by: Jamsheed Mohammed C M <jamsheed.c.m@oracle.com>
Co-authored-by: Jan Lahoda <jan.lahoda@oracle.com>
Co-authored-by: Amy Lu <amy.lu@oracle.com>
Reviewed-by: alanb, cjplummer, coleenp, dholmes, dlong, forax, jlahoda, psandoz, plevart, sspitsyn, vromero
2020-04-21 06:55:38 -07:00
|
|
|
|
2012-10-25 17:34:24 -07:00
|
|
|
private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace";
|
2013-10-29 12:31:27 -04:00
|
|
|
private static final String NAME_METHOD_READ_OBJECT = "readObject";
|
|
|
|
private static final String NAME_METHOD_WRITE_OBJECT = "writeObject";
|
2015-11-05 16:29:16 +01:00
|
|
|
|
|
|
|
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;";
|
2013-02-16 12:36:54 -08:00
|
|
|
private static final String DESCR_CTOR_SERIALIZED_LAMBDA
|
2015-11-05 16:29:16 +01:00
|
|
|
= "(" + 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";
|
2013-10-29 12:31:27 -04:00
|
|
|
private static final String[] SER_HOSTILE_EXCEPTIONS = new String[] {NAME_NOT_SERIALIZABLE_EXCEPTION};
|
|
|
|
|
2013-10-31 10:37:08 -04:00
|
|
|
private static final String[] EMPTY_STRING_ARRAY = new String[0];
|
|
|
|
|
2012-10-25 17:34:24 -07:00
|
|
|
// Used to ensure that each spun class name is unique
|
2020-10-28 12:11:53 +00:00
|
|
|
private static final AtomicInteger counter = new AtomicInteger();
|
2012-10-25 17:34:24 -07:00
|
|
|
|
2013-10-09 09:41:40 -07:00
|
|
|
// For dumping generated classes to disk, for debugging purposes
|
|
|
|
private static final ProxyClassesDumper dumper;
|
|
|
|
|
2019-10-28 15:03:36 +01:00
|
|
|
private static final boolean disableEagerInitialization;
|
|
|
|
|
2020-12-01 00:24:40 +00:00
|
|
|
// condy to load implMethod from class data
|
|
|
|
private static final ConstantDynamic implMethodCondy;
|
|
|
|
|
2013-10-09 09:41:40 -07:00
|
|
|
static {
|
2019-10-28 15:03:36 +01:00
|
|
|
final String dumpProxyClassesKey = "jdk.internal.lambda.dumpProxyClasses";
|
|
|
|
String dumpPath = GetPropertyAction.privilegedGetProperty(dumpProxyClassesKey);
|
|
|
|
dumper = (null == dumpPath) ? null : ProxyClassesDumper.getInstance(dumpPath);
|
|
|
|
|
|
|
|
final String disableEagerInitializationKey = "jdk.internal.lambda.disableEagerInitialization";
|
|
|
|
disableEagerInitialization = GetBooleanAction.privilegedGetProperty(disableEagerInitializationKey);
|
2020-12-01 00:24:40 +00:00
|
|
|
|
|
|
|
// condy to load implMethod from class data
|
2021-10-28 18:32:50 +00:00
|
|
|
MethodType classDataMType = methodType(Object.class, MethodHandles.Lookup.class, String.class, Class.class);
|
2020-12-01 00:24:40 +00:00
|
|
|
Handle classDataBsm = new Handle(H_INVOKESTATIC, Type.getInternalName(MethodHandles.class), "classData",
|
|
|
|
classDataMType.descriptorString(), false);
|
|
|
|
implMethodCondy = new ConstantDynamic(ConstantDescs.DEFAULT_NAME, MethodHandle.class.descriptorString(), classDataBsm);
|
2013-10-09 09:41:40 -07:00
|
|
|
}
|
|
|
|
|
2012-10-25 17:34:24 -07:00
|
|
|
// 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
|
2013-10-31 10:37:08 -04:00
|
|
|
private final String[] argDescs; // Type descriptors for the constructor arguments
|
2012-10-25 17:34:24 -07:00
|
|
|
private final String lambdaClassName; // Generated name for the generated class "X$$Lambda$1"
|
8238358: Implementation of JEP 371: Hidden Classes
Co-authored-by: Lois Foltan <lois.foltan@oracle.com>
Co-authored-by: David Holmes <david.holmes@oracle.com>
Co-authored-by: Harold Seigel <harold.seigel@oracle.com>
Co-authored-by: Serguei Spitsyn <serguei.spitsyn@oracle.com>
Co-authored-by: Alex Buckley <alex.buckley@oracle.com>
Co-authored-by: Jamsheed Mohammed C M <jamsheed.c.m@oracle.com>
Co-authored-by: Jan Lahoda <jan.lahoda@oracle.com>
Co-authored-by: Amy Lu <amy.lu@oracle.com>
Reviewed-by: alanb, cjplummer, coleenp, dholmes, dlong, forax, jlahoda, psandoz, plevart, sspitsyn, vromero
2020-04-21 06:55:38 -07:00
|
|
|
private final boolean useImplMethodHandle; // use MethodHandle invocation instead of symbolic bytecode invocation
|
2012-10-25 17:34:24 -07:00
|
|
|
|
|
|
|
/**
|
2013-07-11 14:02:20 +01:00
|
|
|
* General meta-factory constructor, supporting both standard cases and
|
|
|
|
* allowing for uncommon options such as serialization or bridging.
|
2012-10-25 17:34:24 -07:00
|
|
|
*
|
2013-07-11 14:02:20 +01:00
|
|
|
* @param caller Stacked automatically by VM; represents a lookup context
|
|
|
|
* with the accessibility privileges of the caller.
|
2021-06-07 23:21:24 +00:00
|
|
|
* @param factoryType Stacked automatically by VM; the signature of the
|
2013-07-11 14:02:20 +01:00
|
|
|
* 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.
|
2021-06-07 23:21:24 +00:00
|
|
|
* @param interfaceMethodName Name of the method in the functional interface to
|
|
|
|
* which the lambda or method reference is being
|
|
|
|
* converted, represented as a String.
|
|
|
|
* @param interfaceMethodType Type of the method in the functional interface to
|
|
|
|
* which the lambda or method reference is being
|
|
|
|
* converted, represented as a MethodType.
|
|
|
|
* @param implementation 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 dynamicMethodType The signature of the primary functional
|
|
|
|
* interface method after type variables are
|
|
|
|
* substituted with their instantiation from
|
|
|
|
* the capture site
|
2013-07-11 14:02:20 +01:00
|
|
|
* @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}.
|
2021-06-07 23:21:24 +00:00
|
|
|
* @param altInterfaces Additional interfaces which the lambda object
|
|
|
|
* should implement.
|
|
|
|
* @param altMethods Method types for additional signatures to be
|
|
|
|
* implemented by invoking the implementation method
|
2013-07-11 14:02:20 +01:00
|
|
|
* @throws LambdaConversionException If any of the meta-factory protocol
|
2021-06-07 23:21:24 +00:00
|
|
|
* invariants are violated
|
|
|
|
* @throws SecurityException If a security manager is present, and it
|
|
|
|
* <a href="MethodHandles.Lookup.html#secmgr">denies access</a>
|
|
|
|
* from {@code caller} to the package of {@code implementation}.
|
2012-10-25 17:34:24 -07:00
|
|
|
*/
|
|
|
|
public InnerClassLambdaMetafactory(MethodHandles.Lookup caller,
|
2021-06-07 23:21:24 +00:00
|
|
|
MethodType factoryType,
|
|
|
|
String interfaceMethodName,
|
|
|
|
MethodType interfaceMethodType,
|
|
|
|
MethodHandle implementation,
|
|
|
|
MethodType dynamicMethodType,
|
2013-07-11 14:02:20 +01:00
|
|
|
boolean isSerializable,
|
2021-06-07 23:21:24 +00:00
|
|
|
Class<?>[] altInterfaces,
|
|
|
|
MethodType[] altMethods)
|
2013-10-24 13:06:05 -04:00
|
|
|
throws LambdaConversionException {
|
2021-06-07 23:21:24 +00:00
|
|
|
super(caller, factoryType, interfaceMethodName, interfaceMethodType,
|
|
|
|
implementation, dynamicMethodType,
|
|
|
|
isSerializable, altInterfaces, altMethods);
|
2017-02-13 10:47:15 -07:00
|
|
|
implMethodClassName = implClass.getName().replace('.', '/');
|
2012-10-25 17:34:24 -07:00
|
|
|
implMethodName = implInfo.getName();
|
2017-02-13 10:47:15 -07:00
|
|
|
implMethodDesc = implInfo.getMethodType().toMethodDescriptorString();
|
2021-06-07 23:21:24 +00:00
|
|
|
constructorType = factoryType.changeReturnType(Void.TYPE);
|
8238358: Implementation of JEP 371: Hidden Classes
Co-authored-by: Lois Foltan <lois.foltan@oracle.com>
Co-authored-by: David Holmes <david.holmes@oracle.com>
Co-authored-by: Harold Seigel <harold.seigel@oracle.com>
Co-authored-by: Serguei Spitsyn <serguei.spitsyn@oracle.com>
Co-authored-by: Alex Buckley <alex.buckley@oracle.com>
Co-authored-by: Jamsheed Mohammed C M <jamsheed.c.m@oracle.com>
Co-authored-by: Jan Lahoda <jan.lahoda@oracle.com>
Co-authored-by: Amy Lu <amy.lu@oracle.com>
Reviewed-by: alanb, cjplummer, coleenp, dholmes, dlong, forax, jlahoda, psandoz, plevart, sspitsyn, vromero
2020-04-21 06:55:38 -07:00
|
|
|
lambdaClassName = lambdaClassName(targetClass);
|
2021-06-09 23:57:41 +00:00
|
|
|
// If the target class invokes a protected method inherited from a
|
|
|
|
// superclass in a different package, or does 'invokespecial', the
|
|
|
|
// lambda class has no access to the resolved method. Instead, we need
|
|
|
|
// to pass the live implementation method handle to the proxy class
|
|
|
|
// to invoke directly. (javac prefers to avoid this situation by
|
|
|
|
// generating bridges in the target class)
|
|
|
|
useImplMethodHandle = (Modifier.isProtected(implInfo.getModifiers()) &&
|
2021-07-13 02:24:14 +00:00
|
|
|
!VerifyAccess.isSamePackage(targetClass, implInfo.getDeclaringClass())) ||
|
2021-06-09 23:57:41 +00:00
|
|
|
implKind == H_INVOKESPECIAL;
|
2012-10-25 17:34:24 -07:00
|
|
|
cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
2021-06-07 23:21:24 +00:00
|
|
|
int parameterCount = factoryType.parameterCount();
|
2013-10-31 10:37:08 -04:00
|
|
|
if (parameterCount > 0) {
|
|
|
|
argNames = new String[parameterCount];
|
|
|
|
argDescs = new String[parameterCount];
|
|
|
|
for (int i = 0; i < parameterCount; i++) {
|
|
|
|
argNames[i] = "arg$" + (i + 1);
|
2021-06-07 23:21:24 +00:00
|
|
|
argDescs[i] = BytecodeDescriptor.unparse(factoryType.parameterType(i));
|
2013-10-31 10:37:08 -04:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
argNames = argDescs = EMPTY_STRING_ARRAY;
|
2012-10-25 17:34:24 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
8238358: Implementation of JEP 371: Hidden Classes
Co-authored-by: Lois Foltan <lois.foltan@oracle.com>
Co-authored-by: David Holmes <david.holmes@oracle.com>
Co-authored-by: Harold Seigel <harold.seigel@oracle.com>
Co-authored-by: Serguei Spitsyn <serguei.spitsyn@oracle.com>
Co-authored-by: Alex Buckley <alex.buckley@oracle.com>
Co-authored-by: Jamsheed Mohammed C M <jamsheed.c.m@oracle.com>
Co-authored-by: Jan Lahoda <jan.lahoda@oracle.com>
Co-authored-by: Amy Lu <amy.lu@oracle.com>
Reviewed-by: alanb, cjplummer, coleenp, dholmes, dlong, forax, jlahoda, psandoz, plevart, sspitsyn, vromero
2020-04-21 06:55:38 -07:00
|
|
|
private static String lambdaClassName(Class<?> targetClass) {
|
|
|
|
String name = targetClass.getName();
|
|
|
|
if (targetClass.isHidden()) {
|
|
|
|
// use the original class name
|
|
|
|
name = name.replace('/', '_');
|
|
|
|
}
|
|
|
|
return name.replace('.', '/') + "$$Lambda$" + counter.incrementAndGet();
|
|
|
|
}
|
|
|
|
|
2012-10-25 17:34:24 -07:00
|
|
|
/**
|
|
|
|
* 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
|
2013-07-11 14:02:20 +01:00
|
|
|
* @throws LambdaConversionException If properly formed functional interface
|
|
|
|
* is not found
|
2012-10-25 17:34:24 -07:00
|
|
|
*/
|
|
|
|
@Override
|
2013-10-24 13:06:05 -04:00
|
|
|
CallSite buildCallSite() throws LambdaConversionException {
|
2012-10-25 17:34:24 -07:00
|
|
|
final Class<?> innerClass = spinInnerClass();
|
2021-10-28 18:32:50 +00:00
|
|
|
if (factoryType.parameterCount() == 0 && disableEagerInitialization) {
|
|
|
|
try {
|
|
|
|
return new ConstantCallSite(caller.findStaticGetter(innerClass, LAMBDA_INSTANCE_FIELD,
|
|
|
|
factoryType.returnType()));
|
|
|
|
} catch (ReflectiveOperationException e) {
|
|
|
|
throw new LambdaConversionException(
|
|
|
|
"Exception finding " + LAMBDA_INSTANCE_FIELD + " static field", e);
|
2013-10-24 13:06:05 -04:00
|
|
|
}
|
2012-10-25 17:34:24 -07:00
|
|
|
} else {
|
2013-10-24 13:06:05 -04:00
|
|
|
try {
|
2021-06-07 23:21:24 +00:00
|
|
|
MethodHandle mh = caller.findConstructor(innerClass, constructorType);
|
2021-10-28 18:32:50 +00:00
|
|
|
if (factoryType.parameterCount() == 0) {
|
|
|
|
// In the case of a non-capturing lambda, we optimize linkage by pre-computing a single instance
|
|
|
|
Object inst = mh.asType(methodType(Object.class)).invokeExact();
|
|
|
|
return new ConstantCallSite(MethodHandles.constant(interfaceClass, inst));
|
|
|
|
} else {
|
|
|
|
return new ConstantCallSite(mh.asType(factoryType));
|
|
|
|
}
|
8238358: Implementation of JEP 371: Hidden Classes
Co-authored-by: Lois Foltan <lois.foltan@oracle.com>
Co-authored-by: David Holmes <david.holmes@oracle.com>
Co-authored-by: Harold Seigel <harold.seigel@oracle.com>
Co-authored-by: Serguei Spitsyn <serguei.spitsyn@oracle.com>
Co-authored-by: Alex Buckley <alex.buckley@oracle.com>
Co-authored-by: Jamsheed Mohammed C M <jamsheed.c.m@oracle.com>
Co-authored-by: Jan Lahoda <jan.lahoda@oracle.com>
Co-authored-by: Amy Lu <amy.lu@oracle.com>
Reviewed-by: alanb, cjplummer, coleenp, dholmes, dlong, forax, jlahoda, psandoz, plevart, sspitsyn, vromero
2020-04-21 06:55:38 -07:00
|
|
|
} catch (ReflectiveOperationException e) {
|
2013-10-24 13:06:05 -04:00
|
|
|
throw new LambdaConversionException("Exception finding constructor", e);
|
2021-10-28 18:32:50 +00:00
|
|
|
} catch (Throwable e) {
|
|
|
|
throw new LambdaConversionException("Exception instantiating lambda object", e);
|
2013-10-24 13:06:05 -04:00
|
|
|
}
|
2012-10-25 17:34:24 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-10 15:50:26 +00:00
|
|
|
/**
|
|
|
|
* Spins the lambda proxy class.
|
|
|
|
*
|
|
|
|
* This first checks if a lambda proxy class can be loaded from CDS archive.
|
|
|
|
* Otherwise, generate the lambda proxy class. If CDS dumping is enabled, it
|
|
|
|
* registers the lambda proxy class for including into the CDS archive.
|
|
|
|
*/
|
|
|
|
private Class<?> spinInnerClass() throws LambdaConversionException {
|
2022-07-19 04:37:28 +00:00
|
|
|
// CDS does not handle disableEagerInitialization or useImplMethodHandle
|
|
|
|
if (!disableEagerInitialization && !useImplMethodHandle) {
|
2020-12-02 22:17:46 +00:00
|
|
|
// include lambda proxy class in CDS archive at dump time
|
|
|
|
if (CDS.isDumpingArchive()) {
|
|
|
|
Class<?> innerClass = generateInnerClass();
|
|
|
|
LambdaProxyClassArchive.register(targetClass,
|
2021-06-07 23:21:24 +00:00
|
|
|
interfaceMethodName,
|
|
|
|
factoryType,
|
|
|
|
interfaceMethodType,
|
|
|
|
implementation,
|
|
|
|
dynamicMethodType,
|
2020-12-02 22:17:46 +00:00
|
|
|
isSerializable,
|
2021-06-07 23:21:24 +00:00
|
|
|
altInterfaces,
|
|
|
|
altMethods,
|
2020-12-02 22:17:46 +00:00
|
|
|
innerClass);
|
|
|
|
return innerClass;
|
|
|
|
}
|
2020-06-10 15:50:26 +00:00
|
|
|
|
2020-12-02 22:17:46 +00:00
|
|
|
// load from CDS archive if present
|
|
|
|
Class<?> innerClass = LambdaProxyClassArchive.find(targetClass,
|
2021-06-07 23:21:24 +00:00
|
|
|
interfaceMethodName,
|
|
|
|
factoryType,
|
|
|
|
interfaceMethodType,
|
|
|
|
implementation,
|
|
|
|
dynamicMethodType,
|
2020-12-02 22:17:46 +00:00
|
|
|
isSerializable,
|
2021-06-07 23:21:24 +00:00
|
|
|
altInterfaces,
|
|
|
|
altMethods);
|
2020-12-02 22:17:46 +00:00
|
|
|
if (innerClass != null) return innerClass;
|
2020-06-10 15:50:26 +00:00
|
|
|
}
|
2020-12-02 22:17:46 +00:00
|
|
|
return generateInnerClass();
|
2020-06-10 15:50:26 +00:00
|
|
|
}
|
|
|
|
|
2012-10-25 17:34:24 -07:00
|
|
|
/**
|
|
|
|
* Generate a class file which implements the functional
|
|
|
|
* interface, define and return the class.
|
|
|
|
*
|
|
|
|
* @return a Class which implements the functional interface
|
2013-07-11 14:02:20 +01:00
|
|
|
* @throws LambdaConversionException If properly formed functional interface
|
|
|
|
* is not found
|
2012-10-25 17:34:24 -07:00
|
|
|
*/
|
2021-06-02 11:57:31 +00:00
|
|
|
@SuppressWarnings("removal")
|
2020-06-10 15:50:26 +00:00
|
|
|
private Class<?> generateInnerClass() throws LambdaConversionException {
|
2021-06-07 23:21:24 +00:00
|
|
|
String[] interfaceNames;
|
|
|
|
String interfaceName = interfaceClass.getName().replace('.', '/');
|
|
|
|
boolean accidentallySerializable = !isSerializable && Serializable.class.isAssignableFrom(interfaceClass);
|
|
|
|
if (altInterfaces.length == 0) {
|
|
|
|
interfaceNames = new String[]{interfaceName};
|
2013-10-23 15:16:35 -07:00
|
|
|
} else {
|
|
|
|
// Assure no duplicate interfaces (ClassFormatError)
|
2022-06-09 01:50:54 +00:00
|
|
|
Set<String> itfs = LinkedHashSet.newLinkedHashSet(altInterfaces.length + 1);
|
2021-06-07 23:21:24 +00:00
|
|
|
itfs.add(interfaceName);
|
|
|
|
for (Class<?> i : altInterfaces) {
|
|
|
|
itfs.add(i.getName().replace('.', '/'));
|
|
|
|
accidentallySerializable |= !isSerializable && Serializable.class.isAssignableFrom(i);
|
2013-10-23 15:16:35 -07:00
|
|
|
}
|
2021-06-07 23:21:24 +00:00
|
|
|
interfaceNames = itfs.toArray(new String[itfs.size()]);
|
2013-02-16 12:36:54 -08:00
|
|
|
}
|
2013-10-23 15:16:35 -07:00
|
|
|
|
2013-04-12 20:23:13 -07:00
|
|
|
cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
|
2013-02-16 12:36:54 -08:00
|
|
|
lambdaClassName, null,
|
2021-06-07 23:21:24 +00:00
|
|
|
JAVA_LANG_OBJECT, interfaceNames);
|
2012-10-25 17:34:24 -07:00
|
|
|
|
|
|
|
// Generate final fields to be filled in by constructor
|
2013-10-31 10:37:08 -04:00
|
|
|
for (int i = 0; i < argDescs.length; i++) {
|
2013-07-11 14:02:20 +01:00
|
|
|
FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL,
|
|
|
|
argNames[i],
|
2013-10-31 10:37:08 -04:00
|
|
|
argDescs[i],
|
2013-02-16 12:36:54 -08:00
|
|
|
null, null);
|
2012-10-25 17:34:24 -07:00
|
|
|
fv.visitEnd();
|
|
|
|
}
|
|
|
|
|
|
|
|
generateConstructor();
|
|
|
|
|
2021-06-07 23:21:24 +00:00
|
|
|
if (factoryType.parameterCount() == 0 && disableEagerInitialization) {
|
2020-09-25 10:10:36 +00:00
|
|
|
generateClassInitializer();
|
|
|
|
}
|
|
|
|
|
2012-10-25 17:34:24 -07:00
|
|
|
// Forward the SAM method
|
2021-06-07 23:21:24 +00:00
|
|
|
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, interfaceMethodName,
|
|
|
|
interfaceMethodType.toMethodDescriptorString(), null, null);
|
|
|
|
new ForwardingMethodGenerator(mv).generate(interfaceMethodType);
|
|
|
|
|
|
|
|
// Forward the altMethods
|
|
|
|
if (altMethods != null) {
|
|
|
|
for (MethodType mt : altMethods) {
|
|
|
|
mv = cw.visitMethod(ACC_PUBLIC, interfaceMethodName,
|
2013-10-31 10:37:08 -04:00
|
|
|
mt.toMethodDescriptorString(), null, null);
|
|
|
|
new ForwardingMethodGenerator(mv).generate(mt);
|
2012-10-25 17:34:24 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-11 14:02:20 +01:00
|
|
|
if (isSerializable)
|
2013-10-29 12:31:27 -04:00
|
|
|
generateSerializationFriendlyMethods();
|
|
|
|
else if (accidentallySerializable)
|
|
|
|
generateSerializationHostileMethods();
|
2012-10-25 17:34:24 -07:00
|
|
|
|
|
|
|
cw.visitEnd();
|
|
|
|
|
|
|
|
// Define the generated class in this VM.
|
|
|
|
|
|
|
|
final byte[] classBytes = cw.toByteArray();
|
2013-10-09 09:41:40 -07:00
|
|
|
// If requested, dump out to a file for debugging purposes
|
|
|
|
if (dumper != null) {
|
2015-04-23 09:32:35 -07:00
|
|
|
AccessController.doPrivileged(new PrivilegedAction<>() {
|
2013-10-09 09:41:40 -07:00
|
|
|
@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"));
|
|
|
|
}
|
8238358: Implementation of JEP 371: Hidden Classes
Co-authored-by: Lois Foltan <lois.foltan@oracle.com>
Co-authored-by: David Holmes <david.holmes@oracle.com>
Co-authored-by: Harold Seigel <harold.seigel@oracle.com>
Co-authored-by: Serguei Spitsyn <serguei.spitsyn@oracle.com>
Co-authored-by: Alex Buckley <alex.buckley@oracle.com>
Co-authored-by: Jamsheed Mohammed C M <jamsheed.c.m@oracle.com>
Co-authored-by: Jan Lahoda <jan.lahoda@oracle.com>
Co-authored-by: Amy Lu <amy.lu@oracle.com>
Reviewed-by: alanb, cjplummer, coleenp, dholmes, dlong, forax, jlahoda, psandoz, plevart, sspitsyn, vromero
2020-04-21 06:55:38 -07:00
|
|
|
try {
|
|
|
|
// this class is linked at the indy callsite; so define a hidden nestmate
|
2020-12-01 00:24:40 +00:00
|
|
|
Lookup lookup;
|
8238358: Implementation of JEP 371: Hidden Classes
Co-authored-by: Lois Foltan <lois.foltan@oracle.com>
Co-authored-by: David Holmes <david.holmes@oracle.com>
Co-authored-by: Harold Seigel <harold.seigel@oracle.com>
Co-authored-by: Serguei Spitsyn <serguei.spitsyn@oracle.com>
Co-authored-by: Alex Buckley <alex.buckley@oracle.com>
Co-authored-by: Jamsheed Mohammed C M <jamsheed.c.m@oracle.com>
Co-authored-by: Jan Lahoda <jan.lahoda@oracle.com>
Co-authored-by: Amy Lu <amy.lu@oracle.com>
Reviewed-by: alanb, cjplummer, coleenp, dholmes, dlong, forax, jlahoda, psandoz, plevart, sspitsyn, vromero
2020-04-21 06:55:38 -07:00
|
|
|
if (useImplMethodHandle) {
|
2021-06-07 23:21:24 +00:00
|
|
|
lookup = caller.defineHiddenClassWithClassData(classBytes, implementation, !disableEagerInitialization,
|
2020-12-01 00:24:40 +00:00
|
|
|
NESTMATE, STRONG);
|
|
|
|
} else {
|
|
|
|
lookup = caller.defineHiddenClass(classBytes, !disableEagerInitialization, NESTMATE, STRONG);
|
8238358: Implementation of JEP 371: Hidden Classes
Co-authored-by: Lois Foltan <lois.foltan@oracle.com>
Co-authored-by: David Holmes <david.holmes@oracle.com>
Co-authored-by: Harold Seigel <harold.seigel@oracle.com>
Co-authored-by: Serguei Spitsyn <serguei.spitsyn@oracle.com>
Co-authored-by: Alex Buckley <alex.buckley@oracle.com>
Co-authored-by: Jamsheed Mohammed C M <jamsheed.c.m@oracle.com>
Co-authored-by: Jan Lahoda <jan.lahoda@oracle.com>
Co-authored-by: Amy Lu <amy.lu@oracle.com>
Reviewed-by: alanb, cjplummer, coleenp, dholmes, dlong, forax, jlahoda, psandoz, plevart, sspitsyn, vromero
2020-04-21 06:55:38 -07:00
|
|
|
}
|
|
|
|
return lookup.lookupClass();
|
|
|
|
} catch (IllegalAccessException e) {
|
|
|
|
throw new LambdaConversionException("Exception defining lambda proxy class", e);
|
|
|
|
} catch (Throwable t) {
|
|
|
|
throw new InternalError(t);
|
2013-10-31 10:37:08 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-25 10:10:36 +00:00
|
|
|
/**
|
|
|
|
* Generate a static field and a static initializer that sets this field to an instance of the lambda
|
|
|
|
*/
|
|
|
|
private void generateClassInitializer() {
|
2021-06-07 23:21:24 +00:00
|
|
|
String lambdaTypeDescriptor = factoryType.returnType().descriptorString();
|
2020-09-25 10:10:36 +00:00
|
|
|
|
|
|
|
// Generate the static final field that holds the lambda singleton
|
|
|
|
FieldVisitor fv = cw.visitField(ACC_PRIVATE | ACC_STATIC | ACC_FINAL,
|
|
|
|
LAMBDA_INSTANCE_FIELD, lambdaTypeDescriptor, null, null);
|
|
|
|
fv.visitEnd();
|
|
|
|
|
|
|
|
// Instantiate the lambda and store it to the static final field
|
|
|
|
MethodVisitor clinit = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
|
|
|
|
clinit.visitCode();
|
|
|
|
|
|
|
|
clinit.visitTypeInsn(NEW, lambdaClassName);
|
|
|
|
clinit.visitInsn(Opcodes.DUP);
|
2021-06-07 23:21:24 +00:00
|
|
|
assert factoryType.parameterCount() == 0;
|
2020-09-25 10:10:36 +00:00
|
|
|
clinit.visitMethodInsn(INVOKESPECIAL, lambdaClassName, NAME_CTOR, constructorType.toMethodDescriptorString(), false);
|
|
|
|
clinit.visitFieldInsn(PUTSTATIC, lambdaClassName, LAMBDA_INSTANCE_FIELD, lambdaTypeDescriptor);
|
|
|
|
|
|
|
|
clinit.visitInsn(RETURN);
|
|
|
|
clinit.visitMaxs(-1, -1);
|
|
|
|
clinit.visitEnd();
|
|
|
|
}
|
|
|
|
|
2012-10-25 17:34:24 -07:00
|
|
|
/**
|
|
|
|
* Generate the constructor for the class
|
|
|
|
*/
|
|
|
|
private void generateConstructor() {
|
|
|
|
// Generate constructor
|
2013-07-11 14:02:20 +01:00
|
|
|
MethodVisitor ctor = cw.visitMethod(ACC_PRIVATE, NAME_CTOR,
|
2013-10-31 10:37:08 -04:00
|
|
|
constructorType.toMethodDescriptorString(), null, null);
|
2012-10-25 17:34:24 -07:00
|
|
|
ctor.visitCode();
|
|
|
|
ctor.visitVarInsn(ALOAD, 0);
|
2013-10-20 18:07:40 -07:00
|
|
|
ctor.visitMethodInsn(INVOKESPECIAL, JAVA_LANG_OBJECT, NAME_CTOR,
|
2014-01-17 12:28:59 -05:00
|
|
|
METHOD_DESCRIPTOR_VOID, false);
|
2021-06-07 23:21:24 +00:00
|
|
|
int parameterCount = factoryType.parameterCount();
|
2013-10-31 10:37:08 -04:00
|
|
|
for (int i = 0, lvIndex = 0; i < parameterCount; i++) {
|
2012-10-25 17:34:24 -07:00
|
|
|
ctor.visitVarInsn(ALOAD, 0);
|
2021-06-07 23:21:24 +00:00
|
|
|
Class<?> argType = factoryType.parameterType(i);
|
2013-10-31 10:37:08 -04:00
|
|
|
ctor.visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
|
|
|
|
lvIndex += getParameterSize(argType);
|
|
|
|
ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argDescs[i]);
|
2012-10-25 17:34:24 -07:00
|
|
|
}
|
|
|
|
ctor.visitInsn(RETURN);
|
2013-07-11 14:02:20 +01:00
|
|
|
// Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
|
|
|
|
ctor.visitMaxs(-1, -1);
|
2012-10-25 17:34:24 -07:00
|
|
|
ctor.visitEnd();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-10-29 12:31:27 -04:00
|
|
|
* Generate a writeReplace method that supports serialization
|
2012-10-25 17:34:24 -07:00
|
|
|
*/
|
2013-10-29 12:31:27 -04:00
|
|
|
private void generateSerializationFriendlyMethods() {
|
2013-02-16 12:36:54 -08:00
|
|
|
TypeConvertingMethodAdapter mv
|
2013-07-11 14:02:20 +01:00
|
|
|
= new TypeConvertingMethodAdapter(
|
|
|
|
cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
|
|
|
|
NAME_METHOD_WRITE_REPLACE, DESCR_METHOD_WRITE_REPLACE,
|
|
|
|
null, null));
|
2012-10-25 17:34:24 -07:00
|
|
|
|
|
|
|
mv.visitCode();
|
|
|
|
mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA);
|
2013-07-11 14:02:20 +01:00
|
|
|
mv.visitInsn(DUP);
|
2013-02-26 10:38:58 -08:00
|
|
|
mv.visitLdcInsn(Type.getType(targetClass));
|
2021-06-07 23:21:24 +00:00
|
|
|
mv.visitLdcInsn(factoryType.returnType().getName().replace('.', '/'));
|
|
|
|
mv.visitLdcInsn(interfaceMethodName);
|
|
|
|
mv.visitLdcInsn(interfaceMethodType.toMethodDescriptorString());
|
2013-02-16 12:36:54 -08:00
|
|
|
mv.visitLdcInsn(implInfo.getReferenceKind());
|
|
|
|
mv.visitLdcInsn(implInfo.getDeclaringClass().getName().replace('.', '/'));
|
|
|
|
mv.visitLdcInsn(implInfo.getName());
|
|
|
|
mv.visitLdcInsn(implInfo.getMethodType().toMethodDescriptorString());
|
2021-06-07 23:21:24 +00:00
|
|
|
mv.visitLdcInsn(dynamicMethodType.toMethodDescriptorString());
|
2013-10-31 10:37:08 -04:00
|
|
|
mv.iconst(argDescs.length);
|
2013-10-20 18:07:40 -07:00
|
|
|
mv.visitTypeInsn(ANEWARRAY, JAVA_LANG_OBJECT);
|
2013-10-31 10:37:08 -04:00
|
|
|
for (int i = 0; i < argDescs.length; i++) {
|
2013-02-16 12:36:54 -08:00
|
|
|
mv.visitInsn(DUP);
|
2012-10-25 17:34:24 -07:00
|
|
|
mv.iconst(i);
|
|
|
|
mv.visitVarInsn(ALOAD, 0);
|
2013-10-31 10:37:08 -04:00
|
|
|
mv.visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]);
|
|
|
|
mv.boxIfTypePrimitive(Type.getType(argDescs[i]));
|
2012-10-25 17:34:24 -07:00
|
|
|
mv.visitInsn(AASTORE);
|
|
|
|
}
|
2013-02-16 12:36:54 -08:00
|
|
|
mv.visitMethodInsn(INVOKESPECIAL, NAME_SERIALIZED_LAMBDA, NAME_CTOR,
|
2014-01-17 12:28:59 -05:00
|
|
|
DESCR_CTOR_SERIALIZED_LAMBDA, false);
|
2012-10-25 17:34:24 -07:00
|
|
|
mv.visitInsn(ARETURN);
|
2013-07-11 14:02:20 +01:00
|
|
|
// Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
|
|
|
|
mv.visitMaxs(-1, -1);
|
2012-10-25 17:34:24 -07:00
|
|
|
mv.visitEnd();
|
|
|
|
}
|
|
|
|
|
2013-10-29 12:31:27 -04:00
|
|
|
/**
|
|
|
|
* 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,
|
2014-01-17 12:28:59 -05:00
|
|
|
DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION, false);
|
2013-10-29 12:31:27 -04:00
|
|
|
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,
|
2014-01-17 12:28:59 -05:00
|
|
|
DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION, false);
|
2013-10-29 12:31:27 -04:00
|
|
|
mv.visitInsn(ATHROW);
|
|
|
|
mv.visitMaxs(-1, -1);
|
|
|
|
mv.visitEnd();
|
|
|
|
}
|
|
|
|
|
2012-10-25 17:34:24 -07:00
|
|
|
/**
|
|
|
|
* 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);
|
|
|
|
}
|
|
|
|
|
2013-10-31 10:37:08 -04:00
|
|
|
void generate(MethodType methodType) {
|
2012-10-25 17:34:24 -07:00
|
|
|
visitCode();
|
|
|
|
|
|
|
|
if (implKind == MethodHandleInfo.REF_newInvokeSpecial) {
|
|
|
|
visitTypeInsn(NEW, implMethodClassName);
|
2013-07-11 14:02:20 +01:00
|
|
|
visitInsn(DUP);
|
2012-10-25 17:34:24 -07:00
|
|
|
}
|
8238358: Implementation of JEP 371: Hidden Classes
Co-authored-by: Lois Foltan <lois.foltan@oracle.com>
Co-authored-by: David Holmes <david.holmes@oracle.com>
Co-authored-by: Harold Seigel <harold.seigel@oracle.com>
Co-authored-by: Serguei Spitsyn <serguei.spitsyn@oracle.com>
Co-authored-by: Alex Buckley <alex.buckley@oracle.com>
Co-authored-by: Jamsheed Mohammed C M <jamsheed.c.m@oracle.com>
Co-authored-by: Jan Lahoda <jan.lahoda@oracle.com>
Co-authored-by: Amy Lu <amy.lu@oracle.com>
Reviewed-by: alanb, cjplummer, coleenp, dholmes, dlong, forax, jlahoda, psandoz, plevart, sspitsyn, vromero
2020-04-21 06:55:38 -07:00
|
|
|
if (useImplMethodHandle) {
|
2020-12-01 00:24:40 +00:00
|
|
|
visitLdcInsn(implMethodCondy);
|
8238358: Implementation of JEP 371: Hidden Classes
Co-authored-by: Lois Foltan <lois.foltan@oracle.com>
Co-authored-by: David Holmes <david.holmes@oracle.com>
Co-authored-by: Harold Seigel <harold.seigel@oracle.com>
Co-authored-by: Serguei Spitsyn <serguei.spitsyn@oracle.com>
Co-authored-by: Alex Buckley <alex.buckley@oracle.com>
Co-authored-by: Jamsheed Mohammed C M <jamsheed.c.m@oracle.com>
Co-authored-by: Jan Lahoda <jan.lahoda@oracle.com>
Co-authored-by: Amy Lu <amy.lu@oracle.com>
Reviewed-by: alanb, cjplummer, coleenp, dholmes, dlong, forax, jlahoda, psandoz, plevart, sspitsyn, vromero
2020-04-21 06:55:38 -07:00
|
|
|
}
|
2013-10-31 10:37:08 -04:00
|
|
|
for (int i = 0; i < argNames.length; i++) {
|
2012-10-25 17:34:24 -07:00
|
|
|
visitVarInsn(ALOAD, 0);
|
2013-10-31 10:37:08 -04:00
|
|
|
visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]);
|
2012-10-25 17:34:24 -07:00
|
|
|
}
|
|
|
|
|
2013-10-31 10:37:08 -04:00
|
|
|
convertArgumentTypes(methodType);
|
2012-10-25 17:34:24 -07:00
|
|
|
|
8238358: Implementation of JEP 371: Hidden Classes
Co-authored-by: Lois Foltan <lois.foltan@oracle.com>
Co-authored-by: David Holmes <david.holmes@oracle.com>
Co-authored-by: Harold Seigel <harold.seigel@oracle.com>
Co-authored-by: Serguei Spitsyn <serguei.spitsyn@oracle.com>
Co-authored-by: Alex Buckley <alex.buckley@oracle.com>
Co-authored-by: Jamsheed Mohammed C M <jamsheed.c.m@oracle.com>
Co-authored-by: Jan Lahoda <jan.lahoda@oracle.com>
Co-authored-by: Amy Lu <amy.lu@oracle.com>
Reviewed-by: alanb, cjplummer, coleenp, dholmes, dlong, forax, jlahoda, psandoz, plevart, sspitsyn, vromero
2020-04-21 06:55:38 -07:00
|
|
|
if (useImplMethodHandle) {
|
2021-07-13 02:24:14 +00:00
|
|
|
MethodType mtype = implInfo.getMethodType();
|
|
|
|
if (implKind != MethodHandleInfo.REF_invokeStatic) {
|
|
|
|
mtype = mtype.insertParameterTypes(0, implClass);
|
|
|
|
}
|
8238358: Implementation of JEP 371: Hidden Classes
Co-authored-by: Lois Foltan <lois.foltan@oracle.com>
Co-authored-by: David Holmes <david.holmes@oracle.com>
Co-authored-by: Harold Seigel <harold.seigel@oracle.com>
Co-authored-by: Serguei Spitsyn <serguei.spitsyn@oracle.com>
Co-authored-by: Alex Buckley <alex.buckley@oracle.com>
Co-authored-by: Jamsheed Mohammed C M <jamsheed.c.m@oracle.com>
Co-authored-by: Jan Lahoda <jan.lahoda@oracle.com>
Co-authored-by: Amy Lu <amy.lu@oracle.com>
Reviewed-by: alanb, cjplummer, coleenp, dholmes, dlong, forax, jlahoda, psandoz, plevart, sspitsyn, vromero
2020-04-21 06:55:38 -07:00
|
|
|
visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle",
|
|
|
|
"invokeExact", mtype.descriptorString(), false);
|
|
|
|
} else {
|
|
|
|
// Invoke the method we want to forward to
|
|
|
|
visitMethodInsn(invocationOpcode(), implMethodClassName,
|
|
|
|
implMethodName, implMethodDesc,
|
|
|
|
implClass.isInterface());
|
|
|
|
}
|
2012-10-25 17:34:24 -07:00
|
|
|
// Convert the return value (if any) and return it
|
2013-07-11 14:02:20 +01:00
|
|
|
// Note: if adapting from non-void to void, the 'return'
|
|
|
|
// instruction will pop the unneeded result
|
2017-02-13 10:47:15 -07:00
|
|
|
Class<?> implReturnClass = implMethodType.returnType();
|
2013-10-31 10:37:08 -04:00
|
|
|
Class<?> samReturnClass = methodType.returnType();
|
2017-02-13 10:47:15 -07:00
|
|
|
convertType(implReturnClass, samReturnClass, samReturnClass);
|
2013-10-31 10:37:08 -04:00
|
|
|
visitInsn(getReturnOpcode(samReturnClass));
|
2013-07-11 14:02:20 +01:00
|
|
|
// Maxs computed by ClassWriter.COMPUTE_MAXS,these arguments ignored
|
|
|
|
visitMaxs(-1, -1);
|
2012-10-25 17:34:24 -07:00
|
|
|
visitEnd();
|
|
|
|
}
|
|
|
|
|
2013-10-31 10:37:08 -04:00
|
|
|
private void convertArgumentTypes(MethodType samType) {
|
2012-10-25 17:34:24 -07:00
|
|
|
int lvIndex = 0;
|
2013-10-31 10:37:08 -04:00
|
|
|
int samParametersLength = samType.parameterCount();
|
2021-06-07 23:21:24 +00:00
|
|
|
int captureArity = factoryType.parameterCount();
|
2017-02-13 10:47:15 -07:00
|
|
|
for (int i = 0; i < samParametersLength; i++) {
|
2013-10-31 10:37:08 -04:00
|
|
|
Class<?> argType = samType.parameterType(i);
|
|
|
|
visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
|
|
|
|
lvIndex += getParameterSize(argType);
|
2021-06-07 23:21:24 +00:00
|
|
|
convertType(argType, implMethodType.parameterType(captureArity + i), dynamicMethodType.parameterType(i));
|
2012-10-25 17:34:24 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private int invocationOpcode() throws InternalError {
|
2021-06-10 11:12:37 +00:00
|
|
|
return switch (implKind) {
|
|
|
|
case MethodHandleInfo.REF_invokeStatic -> INVOKESTATIC;
|
|
|
|
case MethodHandleInfo.REF_newInvokeSpecial -> INVOKESPECIAL;
|
|
|
|
case MethodHandleInfo.REF_invokeVirtual -> INVOKEVIRTUAL;
|
|
|
|
case MethodHandleInfo.REF_invokeInterface -> INVOKEINTERFACE;
|
|
|
|
case MethodHandleInfo.REF_invokeSpecial -> INVOKESPECIAL;
|
|
|
|
default -> throw new InternalError("Unexpected invocation kind: " + implKind);
|
|
|
|
};
|
2012-10-25 17:34:24 -07:00
|
|
|
}
|
|
|
|
}
|
2013-10-31 10:37:08 -04:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-25 17:34:24 -07:00
|
|
|
}
|