< prev index next >

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

Print this page
*** 23,11 ***
--- 23,14 ---
   * questions.
   */
  
  package java.lang.reflect;
  
+ import jdk.internal.value.PrimitiveClass;
  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 ***
--- 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

*** 489,20 ***
--- 494,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();
      }

*** 680,10 ***
--- 690,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.
       */

*** 809,10 ***
--- 837,32 ---
              // 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() && !PrimitiveClass.isPrimitiveClass(c)) ||
+                     PrimitiveClass.isPrimitiveValueType(c);
+         }
+ 
          /**
           * 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.

*** 843,11 ***
                          prim.wrapperClassName,
                          prim.unwrapMethodName, prim.unwrapMethodDesc, false);
  
                  mv.visitInsn(prim.returnOpcode);
              } else {
!                 mv.visitTypeInsn(CHECKCAST, dotToSlash(type.getName()));
                  mv.visitInsn(ARETURN);
              }
          }
  
          /**
--- 893,15 ---
                          prim.wrapperClassName,
                          prim.unwrapMethodName, prim.unwrapMethodDesc, false);
  
                  mv.visitInsn(prim.returnOpcode);
              } else {
!                 String internalName = dotToSlash(type.getName());
+                 if (PrimitiveClass.isPrimitiveValueType(type)) {
+                     internalName = 'Q' + internalName + ";";
+                 }
+                 mv.visitTypeInsn(CHECKCAST, internalName);
                  mv.visitInsn(ARETURN);
              }
          }
  
          /**

*** 895,24 ***
           * =============== 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.
           */
          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);
          }
  
          /**
           * Visit a bytecode for a constant.
           *
--- 949,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.  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 >