< prev index next >

src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java

Print this page
@@ -23,10 +23,14 @@
   * 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;

@@ -37,14 +41,16 @@
  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

@@ -453,11 +459,12 @@
      /**
       * 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

@@ -481,13 +488,19 @@
          }
  
          /*
           * 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()) {

@@ -498,10 +511,13 @@
  
                  // Generate code for proxy method
                  pm.generateMethod(this, className);
              }
          }
+         if (preloadClasses.size() > 0) {
+             generatePreloadAttribute(preloadClasses);
+         }
  
          generateStaticInitializer();
          generateLookupAccessor();
          return toByteArray();
      }

@@ -679,10 +695,28 @@
          // 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.
       */

@@ -808,10 +842,31 @@
              // 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.

@@ -842,11 +897,15 @@
                          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);
              }
          }
  
          /**

@@ -894,24 +953,33 @@
           * =============== 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 >