RFR improving the dumping of class files

Paul Sandoz paul.sandoz at oracle.com
Tue Jun 13 23:05:11 UTC 2017


The LambdaFormBuilder has the ability to dump class files but it overwrites previously generated files for the same invoker sub-name.

- dumping uses the same property and technique as that for InvokerBytecodeGenerator.

- anon Q-based LF classes are created under the class prefix "java/lang/invoke/LambdaForm$Value$”, sp L-based and Q-based LF byte codes are generated  under the same directory.

- when dumping the method name (which is unique for debugging, since dumping is considered debugging) is appended to the class name, making the files more identifiable (this is not something done for L-based LF classes, which i think we should change upstream).

Paul.


diff -r ff94d67133d3 src/java.base/share/classes/java/lang/invoke/LambdaFormBuilder.java
--- a/src/java.base/share/classes/java/lang/invoke/LambdaFormBuilder.java	Tue Jun 13 14:54:26 2017 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/LambdaFormBuilder.java	Tue Jun 13 15:55:37 2017 -0700
@@ -56,10 +56,10 @@
 /**
  * Utility class for spinning classfiles associated with lambda forms.
  */
-public class LambdaFormBuilder extends MethodHandleBuilder {
+class LambdaFormBuilder extends MethodHandleBuilder {

     private static final String OBJ     = "java/lang/Object";
-    private static final String CLASS_PREFIX   = "LambdaForm$";
+    private static final String CLASS_PREFIX   = "java/lang/invoke/LambdaForm$Value$";
     private static final String DEFAULT_CLASS  = "MH";
     private static final String LL_SIG  = "(L" + OBJ + ";)L" + OBJ + ";";

@@ -71,6 +71,10 @@
         String className = overrideNames ?
                 CLASS_PREFIX + invokerName.substring(0, p) :
                 CLASS_PREFIX + DEFAULT_CLASS;
+        if (MinimalValueTypes_1_0.DUMP_CLASS_FILES) {
+            // When DUMP_CLASS_FILES is true methodName will have a unique id
+            className = className + "_" + methodName;
+        }
         return MethodHandleBuilder.loadCode(Lookup.IMPL_LOOKUP.in(LambdaForm.class), className, methodName, invokerType.toMethodDescriptorString(),
                 M -> new LambdaFormCodeBuilder(form, M), clazz -> InvokerBytecodeGenerator.resolveInvokerMember(clazz, methodName, invokerType),
                 C -> new LambdaFormBuilder(C, form, invokerType).generateLambdaFormBody());
diff -r ff94d67133d3 src/java.base/share/classes/valhalla/shady/MinimalValueTypes_1_0.java
--- a/src/java.base/share/classes/valhalla/shady/MinimalValueTypes_1_0.java	Tue Jun 13 14:54:26 2017 -0700
+++ b/src/java.base/share/classes/valhalla/shady/MinimalValueTypes_1_0.java	Tue Jun 13 15:55:37 2017 -0700
@@ -24,20 +24,18 @@
  */
 package valhalla.shady;

+import jdk.experimental.bytecode.BasicClassBuilder;
+import jdk.internal.misc.Unsafe;
+import sun.security.action.GetPropertyAction;
+
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.security.AccessController;
 import java.security.ProtectionDomain;
-import java.util.PropertyPermission;
-
-import jdk.experimental.bytecode.BasicClassBuilder;
+import java.util.Properties;

 import static jdk.internal.org.objectweb.asm.Opcodes.*;

-import jdk.internal.misc.Unsafe;
-import sun.security.action.GetPropertyAction;
-
 public class MinimalValueTypes_1_0 {

     public static final int    V53_1                  = 1 << 16 | 53;
@@ -48,14 +46,14 @@
     public static final String DERIVE_VALUE_TYPE_DESC = "Ljvm/internal/value/DeriveValueType;";
     public static final String DERIVE_VT_CLASSNAME_POSTFIX = "$Value";
     public static final int    DERIVE_VT_CLASS_ACCESS = ACC_PUBLIC|ACC_SUPER|ACC_FINAL|ACC_VALUE|ACC_SYNTHETIC;
-    public static String DUMP_CLASS_FILES_DIR;
+
+    public static final boolean DUMP_CLASS_FILES;

     static {
-        final String key = "valhalla.dumpProxyClasses";
-        DUMP_CLASS_FILES_DIR = key == null ? null :
-                AccessController.doPrivileged(
-                new GetPropertyAction(key), null,
-                new PropertyPermission(key , "read"));
+        // Use same property as in j.l.invoke.MethodHandleStatics
+        Properties props = GetPropertyAction.privilegedGetProperties();
+        DUMP_CLASS_FILES = Boolean.parseBoolean(
+                props.getProperty("java.lang.invoke.MethodHandle.DUMP_CLASS_FILES"));
     }

     public static String getValueTypeClassName(ValueTypeDesc valueTypeDesc) {
@@ -137,8 +135,27 @@
         return newBytes;
     }

+    /** debugging flag for saving generated class files */
+    private static final File DUMP_CLASS_FILES_DIR;
+
+    static {
+        if (DUMP_CLASS_FILES) {
+            try {
+                File dumpDir = new File("DUMP_CLASS_FILES");
+                if (!dumpDir.exists()) {
+                    dumpDir.mkdirs();
+                }
+                DUMP_CLASS_FILES_DIR = dumpDir;
+            } catch (Exception e) {
+                throw new InternalError(e);
+            }
+        } else {
+            DUMP_CLASS_FILES_DIR = null;
+        }
+    }
+
     public static void maybeDump(final String className, final byte[] classFile) {
-        if (DUMP_CLASS_FILES_DIR != null) {
+        if (DUMP_CLASS_FILES) {
             java.security.AccessController.doPrivileged(
                     new java.security.PrivilegedAction<>() {
                         public Void run() {
@@ -146,13 +163,14 @@
                                 String dumpName = className;
                                 //dumpName = dumpName.replace('/', '-');
                                 File dumpFile = new File(DUMP_CLASS_FILES_DIR, dumpName+".class");
+                                System.out.println("dump: " + dumpFile);
                                 dumpFile.getParentFile().mkdirs();
                                 FileOutputStream file = new FileOutputStream(dumpFile);
                                 file.write(classFile);
                                 file.close();
                                 return null;
                             } catch (IOException ex) {
-                                throw new IllegalStateException(ex);
+                                throw new InternalError(ex);
                             }
                         }
                     });



More information about the valhalla-dev mailing list