< prev index next > src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java
Print this page
* questions.
*/
package java.lang.reflect;
+ import jdk.internal.misc.PreviewFeatures;
+ import jdk.internal.org.objectweb.asm.Attribute;
+ import jdk.internal.org.objectweb.asm.ByteVector;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.Label;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.Type;
import java.lang.invoke.MethodType;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
+ import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
+ import java.util.Set;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
/**
* ProxyGenerator contains the code to generate a dynamic proxy class
/**
* Generate a class file for the proxy class. This method drives the
* class file generation process.
*/
private byte[] generateClassFile() {
- visit(CLASSFILE_VERSION, accessFlags, dotToSlash(className), null,
+ int version = CLASSFILE_VERSION | (PreviewFeatures.isEnabled() ? Opcodes.V_PREVIEW : 0);
+ visit(version, accessFlags, dotToSlash(className), null,
JLR_PROXY, typeNames(interfaces));
/*
* Add proxy methods for the hashCode, equals,
* and toString methods of java.lang.Object. This is done before
}
/*
* For each set of proxy methods with the same signature,
* verify that the methods' return types are compatible.
+ *
+ * Determine if any value classes to be preloaded.
*/
+ Set<Class<?>> preloadClasses = new HashSet<>();
for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
checkReturnTypes(sigmethods);
+ for (ProxyMethod pm : sigmethods) {
+ preloadClasses.addAll(pm.preloadClasses());
+ }
}
generateConstructor();
for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
// Generate code for proxy method
pm.generateMethod(this, className);
}
}
+ if (preloadClasses.size() > 0) {
+ generatePreloadAttribute(preloadClasses);
+ }
generateStaticInitializer();
generateLookupAccessor();
return toByteArray();
}
// Maxs computed by ClassWriter.COMPUTE_FRAMES, these arguments ignored
mv.visitMaxs(-1, -1);
mv.visitEnd();
}
+ private void generatePreloadAttribute(Set<Class<?>> preloadClasses) {
+ Attribute attr = new Attribute("Preload") {
+ @Override
+ protected ByteVector write(ClassWriter cw,
+ byte[] code,
+ int len,
+ int maxStack,
+ int maxLocals) {
+ ByteVector attr = new ByteVector();
+ attr.putShort(preloadClasses.size());
+ for (Class<?> c : preloadClasses) {
+ attr.putShort(cw.newClass(Type.getInternalName(c)));
+ }
+ return attr;
+ }
+ };
+ visitAttribute(attr);
+ }
/**
* A ProxyMethod object represents a proxy method in the proxy class
* being generated: a method whose implementation will encode and
* dispatch invocations to the proxy instance's invocation handler.
*/
// Maxs computed by ClassWriter.COMPUTE_FRAMES, these arguments ignored
mv.visitMaxs(-1, -1);
mv.visitEnd();
}
+ Set<Class<?>> preloadClasses() {
+ Set<Class<?>> preloadClasses = new HashSet<>();
+ for (Class<?> type : parameterTypes) {
+ if (requiresPreload(type)) {
+ preloadClasses.add(type);
+ }
+ }
+ if (requiresPreload(returnType)) {
+ preloadClasses.add(returnType);
+ }
+ return preloadClasses;
+ }
+
+ boolean requiresPreload(Class<?> cls) {
+ Class<?> c = cls;
+ while (c.isArray()) {
+ c = c.getComponentType();
+ }
+ return c.isValue();
+ }
+
/**
* Generate code for wrapping an argument of the given type
* whose value can be found at the specified local variable
* index, in order for it to be passed (as an Object) to the
* invocation handler's "invoke" method.
/**
* Generate code to invoke the Class.forName with the name of the given
* class to get its Class object at runtime. The code is written to
* the supplied stream. Note that the code generated by this method
- * may cause the checked ClassNotFoundException to be thrown. A class
+ * may caused the checked ClassNotFoundException to be thrown. A class
* loader is anticipated at local variable index 0.
*/
private void codeClassForName(MethodVisitor mv, Class<?> cl) {
mv.visitLdcInsn(cl.getName());
mv.visitInsn(ICONST_0); // false
< prev index next >