< prev index next >

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

Print this page
@@ -24,10 +24,12 @@
   */
  
  package java.lang.reflect;
  
  import jdk.internal.misc.VM;
+ 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;

@@ -38,14 +40,16 @@
  import java.nio.file.Files;
  import java.nio.file.Path;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.HashMap;
+ 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

@@ -488,20 +492,25 @@
              checkReturnTypes(sigmethods);
          }
  
          generateConstructor();
  
+         Set<Class<?>> preloadClasses = new HashSet<>();
          for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
              for (ProxyMethod pm : sigmethods) {
                  // add static field for the Method object
                  visitField(ACC_PRIVATE | ACC_STATIC | ACC_FINAL, pm.methodFieldName,
                          LJLR_METHOD, null, null);
  
                  // Generate code for proxy method
                  pm.generateMethod(this, className);
+                 preloadClasses.addAll(pm.preloadClasses());
              }
          }
+         if (preloadClasses.size() > 0) {
+             generatePreloadAttribute(preloadClasses);
+         }
  
          generateStaticInitializer();
          generateLookupAccessor();
          return toByteArray();
      }

@@ -672,10 +681,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.
       */

@@ -801,10 +828,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() && !c.isPrimitiveClass()) || c.isPrimitiveValueType();
+         }
+ 
          /**
           * 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.

@@ -863,11 +911,15 @@
                      mv.visitInsn(DRETURN);
                  } else {
                      throw new AssertionError();
                  }
              } else {
-                 mv.visitTypeInsn(CHECKCAST, dotToSlash(type.getName()));
+                 String internalName = dotToSlash(type.getName());
+                 if (type.isPrimitiveValueType()) {
+                     internalName = 'Q' + internalName + ";";
+                 }
+                 mv.visitTypeInsn(CHECKCAST, internalName);
                  mv.visitInsn(ARETURN);
              }
          }
  
          /**

@@ -914,19 +966,26 @@
           * =============== 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.
+          * 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.
           */
          private void codeClassForName(MethodVisitor mv, Class<?> cl) {
              mv.visitLdcInsn(cl.getName());
              mv.visitMethodInsn(INVOKESTATIC,
                      JL_CLASS,
                      "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false);
+             if (cl.isPrimitiveValueType()) {
+               mv.visitMethodInsn(INVOKEVIRTUAL,
+                                  JL_CLASS,
+                                  "asValueType", "()Ljava/lang/Class;", false);
+             }
          }
  
          /**
           * Visit a bytecode for a constant.
           *
< prev index next >