changeset 3519:a7d38b363cf5

Summary: Code generation for value capable classes should use typed prefix for local loads, stores and returns.
author sadayapalam
date Tue, 04 Oct 2016 15:56:08 +0530
parents 30469b6d88b6
children 54649cba25f1
files src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Items.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/PoolWriter.java test/tools/javac/valhalla/minimalvalues/TypedBytecodeTest.java test/tools/javac/valhalla/minimalvalues/VBytecodeTest.java
diffstat 7 files changed, 294 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Mon Oct 03 13:09:38 2016 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Tue Oct 04 15:56:08 2016 +0530
@@ -312,6 +312,10 @@
                                     : t.tsym != null && (t.tsym.flags_field & Flags.VALUE) != 0;
     }
 
+    public boolean isValueCapable(Type t) {
+        return t != null && t.tsym != null && (t.tsym.flags_field & VALUE_CAPABLE) != 0;
+    }
+
     public boolean requiresThreadLocalBackingBuffer(Type t) {
         return isValue(t) || isAnyTypeVar(t);
     }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Mon Oct 03 13:09:38 2016 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Tue Oct 04 15:56:08 2016 +0530
@@ -88,6 +88,7 @@
     public static final int INITIAL_BUFFER_SIZE = 0x0fff0;
 
     private final Annotate annotate;
+    private final boolean enableMinimalValueTypes;
 
     /** Switch: verbose output.
      */
@@ -235,6 +236,8 @@
         lintClassfile = Lint.instance(context).isEnabled(LintCategory.CLASSFILE);
 
         initAttributeReaders();
+
+        enableMinimalValueTypes = options.isSet("enableMinimalValueTypes");
     }
 
     /** Add member to class unless it is synthetic.
@@ -1205,7 +1208,7 @@
                         target = proxy;
                     } else if (proxy.type.tsym == syms.repeatableType.tsym) {
                         repeatable = proxy;
-                    } else if (sym.kind == TYP && proxy.type.tsym == syms.deriveValueType.tsym) {
+                    } else if (enableMinimalValueTypes && sym.kind == TYP && proxy.type.tsym == syms.deriveValueType.tsym) {
                         sym.flags_field |= VALUE_CAPABLE;
                     }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Mon Oct 03 13:09:38 2016 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Tue Oct 04 15:56:08 2016 +0530
@@ -1906,8 +1906,13 @@
             code.pendingStatPos = tmpPos;
             r.load();
             emitAndMarkIfNeeded1(returnType, types::isSpecializableTypeVar,
-                    () -> code.emitop0(types.isValue(returnType) ? vreturn :
-                            (ireturn + Code.truncate(Code.typecode(erasedReturnType)))));
+                    () -> {
+                        if (types.isValueCapable(returnType)) {
+                            code.emitop2(typed, pool.putValueCapableClass(returnType));
+                        }
+                        code.emitop0(types.isValue(returnType) ? vreturn :
+                                (ireturn + Code.truncate(Code.typecode(erasedReturnType))));
+                    });
         } else {
             /*  If we have a statement like:
              *
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Items.java	Mon Oct 03 13:09:38 2016 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Items.java	Tue Oct 04 15:56:08 2016 +0530
@@ -738,10 +738,14 @@
         }
 
         Item load() {
-            if (types.isValue(type))
+            if (types.isValue(type)) {
                 code.emitop1w(vload, 0);
-            else
+            } else {
+                if (types.isValueCapable(type)) {
+                    code.emitop2(typed, pool.putValueCapableClass(type));
+                }
                 code.emitop0(aload_0);
+            }
             return stackItem[typecode];
         }
 
@@ -776,23 +780,33 @@
 
         Item load() {
             int targetcode = typecode;
-            if (types.isValue(type))
+            if (types.isValue(type)) {
                 code.emitop1w(vload, reg);
-            else if (reg <= 3)
-                code.emitop0(iload_0 + Code.truncate(targetcode) * 4 + reg);
-            else
-                code.emitop1w(iload + Code.truncate(targetcode), reg);
+            } else {
+                if (types.isValueCapable(type)) {
+                    code.emitop2(typed, pool.putValueCapableClass(type));
+                }
+                if (reg <= 3)
+                    code.emitop0(iload_0 + Code.truncate(targetcode) * 4 + reg);
+                else
+                    code.emitop1w(iload + Code.truncate(targetcode), reg);
+            }
             return stackItem[typecode];
         }
 
         void store() {
             int targetcode = typecode;
-            if (types.isValue(type))
+            if (types.isValue(type)) {
                 code.emitop1w(vstore, reg);
-            else if (reg <= 3)
-                code.emitop0(istore_0 + Code.truncate(targetcode) * 4 + reg);
-            else
-                code.emitop1w(istore + Code.truncate(targetcode), reg);
+            } else {
+                if (types.isValueCapable(type)) {
+                    code.emitop2(typed, pool.putValueCapableClass(type));
+                }
+                if (reg <= 3)
+                    code.emitop0(istore_0 + Code.truncate(targetcode) * 4 + reg);
+                else
+                    code.emitop1w(istore + Code.truncate(targetcode), reg);
+            }
             code.setDefined(reg);
         }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/PoolWriter.java	Mon Oct 03 13:09:38 2016 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/PoolWriter.java	Tue Oct 04 15:56:08 2016 +0530
@@ -187,9 +187,20 @@
     }
 
     /**
+     * Puts a value capable class type into the pool and returns the index of the resulting entry.
+     * Note: if a matching entry is already in the pool, no new entry is persisted.
+     */
+    int putValueCapableClass(Type t) {
+        return makeClass(t, this::typeToValueCapableClassName).index;
+    }
+
+    private ClassRef makeClass(Type ct) {
+        return makeClass(ct, this::typeToClassName);
+    }
+    /**
      * Create a new class reference entry from given type.
      */
-    private ClassRef makeClass(Type ct) {
+    private ClassRef makeClass(Type ct, Function<Type, Name> typeNameFunction) {
         if (ct.isCompound()) {
             //intersection types are not supported
             ct = types.directSupertypes(ct).head;
@@ -200,7 +211,7 @@
         if (ct.hasTag(CLASS)) {
             enterInner((ClassSymbol)ct.tsym);
         }
-        Entry clazz = makeType(ct, this::typeToClassName);
+        Entry clazz = makeType(ct, typeNameFunction);
         ClassRef cref = new ClassRef(clazz, ct);
         return (ClassRef)pool.put(cref);
     }
@@ -424,6 +435,16 @@
     }
 
     /**
+     * Helper function: retrieves class name associated with given type.
+     */
+    private Name typeToValueCapableClassName(Type t) {
+        Name name = typeToSig(t);
+        return name.toString().startsWith("L") ?
+                types.names.fromString("Q" + name.toString().substring(1, name.length() - 1)) :
+                name;
+    }
+
+    /**
      * Create a new entry entry from given type.
      */
     private Entry makeType(Type t, Function<Type, Name> typeNameFunction) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/TypedBytecodeTest.java	Tue Oct 04 15:56:08 2016 +0530
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Check that javac emits typed + {aload|astore|areturn} and not vload|vstore|vreturn
+ * @compile -XDenableMinimalValueTypes TypedBytecodeTest.java
+ * @run main TypedBytecodeTest
+ * @modules jdk.compiler
+ */
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.file.Paths;
+
+public class TypedBytecodeTest {
+
+    @jvm.internal.value.DeriveValueType
+    static final class Point {
+
+        final int x;
+        final int y;
+
+        Point (int x, int y) {
+            this.x = x;
+            this.y = y;
+        }
+
+        static Point closestToOrigin(Point p1, Point p2) {
+            double p1Dist = Math.sqrt(p1.x * p1.x + p1.y * p1.y);
+            double p2Dist = Math.sqrt(p2.x * p2.x + p2.y * p2.y);
+            Point result = p1Dist > p2Dist ? p2 : p1;
+            return result;
+        }
+    }
+
+    public static void main(String[] args) {
+        new TypedBytecodeTest().run();
+    }
+
+    void run() {
+        String [] params = new String [] { "-v",
+                                            Paths.get(System.getProperty("test.classes"),
+                                                "TypedBytecodeTest$Point.class").toString() };
+        runCheck(params, new String [] {
+
+           "#12 = Utf8               QTypedBytecodeTest$Point",
+           "#13 = Class              #12            // QTypedBytecodeTest$Point",
+
+           "4: typed         #13                 // class QTypedBytecodeTest$Point",
+           "7: aload_0",
+           "8: iload_1",
+           "9: putfield      #17                 // Field x:I",
+          "12: typed         #13                 // class QTypedBytecodeTest$Point",
+          "15: aload_0",
+          "16: iload_2",
+          "17: putfield      #20                 // Field y:I",
+          "20: return",
+
+           "0: typed         #13                 // class QTypedBytecodeTest$Point",
+           "3: aload_0",
+           "4: getfield      #17                 // Field x:I",
+           "7: typed         #13                 // class QTypedBytecodeTest$Point",
+           "10: aload_0",
+           "11: getfield      #17                 // Field x:I",
+           "14: imul",
+           "15: typed         #13                 // class QTypedBytecodeTest$Point",
+           "18: aload_0",
+           "19: getfield      #20                 // Field y:I",
+           "22: typed         #13                 // class QTypedBytecodeTest$Point",
+           "25: aload_0",
+           "26: getfield      #20                 // Field y:I",
+           "29: imul",
+           "30: iadd",
+           "31: i2d",
+           "32: invokestatic  #26                 // Method java/lang/Math.sqrt:(D)D",
+           "35: dstore_2",
+           "36: typed         #13                 // class QTypedBytecodeTest$Point",
+           "39: aload_1",
+           "40: getfield      #17                 // Field x:I",
+           "43: typed         #13                 // class QTypedBytecodeTest$Point",
+           "46: aload_1",
+           "47: getfield      #17                 // Field x:I",
+           "50: imul",
+           "51: typed         #13                 // class QTypedBytecodeTest$Point",
+           "54: aload_1",
+           "55: getfield      #20                 // Field y:I",
+           "58: typed         #13                 // class QTypedBytecodeTest$Point",
+           "61: aload_1",
+           "62: getfield      #20                 // Field y:I",
+           "65: imul",
+           "66: iadd",
+           "67: i2d",
+           "68: invokestatic  #26                 // Method java/lang/Math.sqrt:(D)D",
+           "71: dstore        4",
+           "73: dload_2",
+           "74: dload         4",
+           "76: dcmpl",
+           "77: ifle          87",
+           "80: typed         #13                 // class QTypedBytecodeTest$Point",
+           "83: aload_1",
+           "84: goto          91",
+           "87: typed         #13                 // class QTypedBytecodeTest$Point",
+           "90: aload_0",
+           "91: typed         #13                 // class QTypedBytecodeTest$Point",
+           "94: astore        6",
+           "96: typed         #13                 // class QTypedBytecodeTest$Point",
+           "99: aload         6",
+          "101: typed         #13                 // class QTypedBytecodeTest$Point",
+          "104: areturn"
+                         });
+
+     }
+
+     void runCheck(String [] params, String [] expectedOut) {
+        StringWriter s;
+        String out;
+
+        try (PrintWriter pw = new PrintWriter(s = new StringWriter())) {
+            com.sun.tools.javap.Main.run(params, pw);
+            out = s.toString();
+        }
+        int errors = 0;
+        for (String eo: expectedOut) {
+            if (!out.contains(eo)) {
+                System.err.println("Match not found for string: " + eo);
+                errors++;
+            }
+        }
+         if (errors > 0) {
+             throw new AssertionError("Unexpected javap output: " + out);
+         }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/VBytecodeTest.java	Tue Oct 04 15:56:08 2016 +0530
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Check that javac emits vload|vstore|vreturn when run without -XDenableMinimalValueTypes
+ * @compile VBytecodeTest.java
+ * @run main VBytecodeTest
+ * @modules jdk.compiler
+ */
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.file.Paths;
+
+public class VBytecodeTest {
+
+    @jvm.internal.value.DeriveValueType
+    static final class Point {
+
+        final int x;
+        final int y;
+
+        Point (int x, int y) {
+            this.x = x;
+            this.y = y;
+        }
+
+        static Point closestToOrigin(Point p1, Point p2) {
+            double p1Dist = Math.sqrt(p1.x * p1.x + p1.y * p1.y);
+            double p2Dist = Math.sqrt(p2.x * p2.x + p2.y * p2.y);
+            Point result = p1Dist > p2Dist ? p2 : p1;
+            return result;
+        }
+    }
+
+    public static void main(String[] args) {
+        new VBytecodeTest().run();
+    }
+
+    void run() {
+        String [] params = new String [] { "-v",
+                                            Paths.get(System.getProperty("test.classes"),
+                                                "VBytecodeTest$Point.class").toString() };
+        StringWriter s;
+        String out;
+
+        try (PrintWriter pw = new PrintWriter(s = new StringWriter())) {
+            com.sun.tools.javap.Main.run(params, pw);
+            out = s.toString();
+        }
+        if (out.contains("typed ")) {
+            throw new AssertionError("Unexpected javap output: " + out);
+        }
+    }
+}
\ No newline at end of file