< prev index next >

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

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

*** 37,14 ***
--- 40,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 ***
      /**
       * 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,
                  JLR_PROXY, typeNames(interfaces));
  
          /*
           * Add proxy methods for the hashCode, equals,
           * and toString methods of java.lang.Object.  This is done before
--- 458,12 ---
      /**
       * Generate a class file for the proxy class.  This method drives the
       * class file generation process.
       */
      private byte[] generateClassFile() {
!         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 ***
--- 487,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 ***
--- 510,13 ---
  
                  // Generate code for proxy method
                  pm.generateMethod(this, className);
              }
          }
+         if (preloadClasses.size() > 0) {
+             generatePreloadAttribute(preloadClasses);
+         }
  
          generateStaticInitializer();
          generateLookupAccessor();
          return toByteArray();
      }

*** 679,10 ***
--- 694,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 ***
--- 841,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.

*** 894,14 ***
           * =============== 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
--- 948,16 ---
           * =============== 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
< prev index next >