< 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.value.PrimitiveClass;
+ 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.
prim.wrapperClassName,
prim.unwrapMethodName, prim.unwrapMethodDesc, false);
mv.visitInsn(prim.returnOpcode);
} else {
- mv.visitTypeInsn(CHECKCAST, dotToSlash(type.getName()));
+ String internalName = dotToSlash(type.getName());
+ if (PrimitiveClass.isPrimitiveValueType(type)) {
+ internalName = 'Q' + internalName + ";";
+ }
+ mv.visitTypeInsn(CHECKCAST, internalName);
mv.visitInsn(ARETURN);
}
}
/**
* =============== Code Generation Utility Methods ===============
*/
/**
* 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
- * loader is anticipated at local variable index 0.
+ * class to get its Class object at runtime. And also generate code
+ * to invoke Class::asValueType if the class is a primitive value type.
+ *
+ * The code is written to the supplied stream. Note that the code generated
+ * by this method 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
mv.visitVarInsn(ALOAD, 0); // classLoader
mv.visitMethodInsn(INVOKESTATIC,
JL_CLASS,
"forName",
"(Ljava/lang/String;Z" + LJL_CLASSLOADER + ")Ljava/lang/Class;",
false);
+ if (PrimitiveClass.isPrimitiveValueType(cl)) {
+ mv.visitMethodInsn(INVOKESTATIC,
+ "jdk/internal/value/PrimitiveClass",
+ "asValueType", "(Ljava/lang/Class;)Ljava/lang/Class;",
+ false);
+ }
+
}
/**
* Visit a bytecode for a constant.
*
< prev index next >