changeset 53179:5853bd189392 lworld

Generate indy for value hashCode/equals/toString with receiver type
author mchung
date Wed, 12 Dec 2018 10:08:39 -0800
parents 6c828d9cf6e8
children b890823b8dc6
files src/java.base/share/classes/java/lang/invoke/ValueBootstrapMethods.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java test/jdk/valhalla/valuetypes/ValueBootstrapMethods.java test/langtools/tools/javac/valhalla/lworld-values/BoxValCastTest.java test/langtools/tools/javac/valhalla/lworld-values/QTypeTest.java test/langtools/tools/javac/valhalla/lworld-values/ValueBootstrapMethodsTest.java
diffstat 7 files changed, 72 insertions(+), 149 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/lang/invoke/ValueBootstrapMethods.java	Wed Dec 12 10:07:38 2018 -0800
+++ b/src/java.base/share/classes/java/lang/invoke/ValueBootstrapMethods.java	Wed Dec 12 10:08:39 2018 -0800
@@ -34,6 +34,7 @@
 import java.util.stream.Stream;
 
 import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
+import static java.lang.invoke.MethodHandles.*;
 import static java.lang.invoke.MethodType.*;
 
 /**
@@ -111,9 +112,6 @@
             case "valueHashCode":
                 mt = methodType(int.class, MethodHandle.class, Object.class);
                 break;
-            case "longHashCode":
-                mt = methodType(long.class, MethodHandle.class, Object.class);
-                break;
             case "equals":
                 mt = methodType(boolean.class, MethodHandle.class, Object.class, Object.class);
                 break;
@@ -127,7 +125,7 @@
             // return the method handle that implements the named method
             // which first invokes the getters method handle of a value object
             // and then compute the result
-            return IMPL_LOOKUP.findStatic(ValueBootstrapMethods.class, name, mt).bindTo(mh);
+            return IMPL_LOOKUP.findStatic(ValueBootstrapMethods.class, name, mt).bindTo(mh).asType(type);
         } catch (ReflectiveOperationException e) {
             throw new BootstrapMethodError(e);
         }
@@ -161,17 +159,15 @@
          */
         static MethodHandle build(MethodHandles.Lookup lookup) {
             // build a MethodHandle[] { Class, getter1, getter2, ...} for the lookup class
-            Class<?> c = lookup.lookupClass().asValueType();
-            MethodHandle valueClass =
-                MethodHandles.dropArguments(MethodHandles.constant(Class.class, c), 0, Object.class);
+            Class<?> type = lookup.lookupClass().asValueType();
+            MethodHandle valueClass = dropArguments(constant(Class.class, type), 0, Object.class);
             MethodHandle[] getters = Stream.concat(Stream.of(valueClass), fields(lookup))
                                            .toArray(MethodHandle[]::new);
 
-            MethodHandle iterations =
-                MethodHandles.dropArguments(MethodHandles.constant(int.class, getters.length), 0, Object.class);
+            MethodHandle iterations = dropArguments(constant(int.class, getters.length), 0, Object.class);
             MethodHandle init = ValueBsmFactory.NEW_ARRAY.bindTo(getters);
             MethodHandle body = ValueBsmFactory.GET_FIELD_VALUE.bindTo(getters);
-            return MethodHandles.countedLoop(iterations, init, body);
+            return countedLoop(iterations, init, body);
         }
 
         static Object[] newObjectArray(MethodHandle[] getters) {
@@ -204,19 +200,6 @@
         return isValue(obj) ? valueHashCode(getters, obj) : obj.hashCode();
     }
 
-    private static long longHashCode(MethodHandle getters, Object obj) {
-        if (isValue(obj)) {
-            Object[] values = invoke(getters, obj);
-            long hash = 1;
-            for (Object o : values) {
-                hash = 31 * hash + o.hashCode();
-            }
-            return hash;
-        } else {
-            return obj.hashCode();
-        }
-    }
-
     private static int valueHashCode(MethodHandle getters, Object obj) {
         if (!isValue(obj)) {
             throw new IllegalArgumentException(obj + " not value type");
@@ -268,5 +251,4 @@
             throw new InternalError(e);
         }
     }
-
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java	Wed Dec 12 10:07:38 2018 -0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java	Wed Dec 12 10:08:39 2018 -0800
@@ -1008,7 +1008,7 @@
          */
         private void addValueMembers(JCClassDecl tree, Env<AttrContext> env) {
 
-            boolean requireHashCode = true, requireEquals = true, requireToString = true, requireLongHashCode = true;
+            boolean requireHashCode = true, requireEquals = true, requireToString = true;
 
             for (JCTree def : tree.defs) {
                 if (def.getTag() == METHODDEF) {
@@ -1025,8 +1025,6 @@
                                     requireHashCode = false;
                                 else if (name.equals("toString"))
                                     requireToString = false;
-                                else if (name.equals("longHashCode"))
-                                    requireLongHashCode = false;
                                 break;
                             case 1:
                                 name = methodDecl.name.toString();
@@ -1092,20 +1090,6 @@
                 tree.defs = tree.defs.append(toString);
             }
 
-            if (requireLongHashCode) {
-                // public long longHashCode() { throw new RuntimeException(message); }
-                JCMethodDecl longHashCode = make.
-                        MethodDef(make.Modifiers(Flags.PUBLIC | Flags.FINAL),
-                                names.fromString("longHashCode"),
-                                make.TypeIdent(TypeTag.LONG),
-                                List.nil(),
-                                List.nil(),
-                                List.nil(), // thrown
-                                body,
-                                null);
-                memberEnter.memberEnter(longHashCode, env);
-                tree.defs = tree.defs.append(longHashCode);
-            }
         }
     }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Wed Dec 12 10:07:38 2018 -0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Wed Dec 12 10:08:39 2018 -0800
@@ -1023,22 +1023,17 @@
             switch (methodDecl.name.toString()) {
                 case "hashCode":
                     name = names.hashCode;
-                    argTypes = List.of(syms.objectType);
+                    argTypes = List.of(methodDecl.sym.owner.type);
                     resType = methodDecl.restype.type;
                     break;
                 case "equals":
                     name = names.equals;
-                    argTypes = List.of(syms.objectType, syms.objectType);
+                    argTypes = List.of(methodDecl.sym.owner.type, syms.objectType);
                     resType = methodDecl.restype.type;
                     break;
                 case "toString":
                     name = names.toString;
-                    argTypes = List.of(syms.objectType);
-                    resType = methodDecl.restype.type;
-                    break;
-                case "longHashCode":
-                    name = names.fromString("longHashCode");
-                    argTypes = List.of(syms.objectType);
+                    argTypes = List.of(methodDecl.sym.owner.type);
                     resType = methodDecl.restype.type;
                     break;
                 default:
@@ -1086,11 +1081,6 @@
                     items.makeDynamicItem(dynSym).invoke();
                     code.emitop0(areturn);
                     return;
-                case "longHashCode":
-                    code.emitop0(aload_0);
-                    items.makeDynamicItem(dynSym).invoke();
-                    code.emitop0(lreturn);
-                    return;
             }
         }
 
--- a/test/jdk/valhalla/valuetypes/ValueBootstrapMethods.java	Wed Dec 12 10:07:38 2018 -0800
+++ b/test/jdk/valhalla/valuetypes/ValueBootstrapMethods.java	Wed Dec 12 10:08:39 2018 -0800
@@ -60,19 +60,16 @@
         Class<?> test = valueTestClass();
         Value value = Value.make(10, 5.03, "foo", "bar", "goo");
 
-        Method hashCode = test.getMethod("hashCode", Object.class);
+        Class<?> valueClass = Value.class.asValueType();
+        Method hashCode = test.getMethod("hashCode", valueClass);
         int hash = (int)hashCode.invoke(null, value);
         assertEquals(hash, value.hashCode());
 
-        Method longHashCode = test.getMethod("longHashCode", Object.class);
-        long lHash = (long)longHashCode.invoke(null, value);
-        assertEquals(lHash, value.longHashCode());
-
-        Method toString = test.getMethod("toString", Object.class);
+        Method toString = test.getMethod("toString", valueClass);
         String s = (String)toString.invoke(null, value);
         assertEquals(s, value.toString());
 
-        Method equals = test.getMethod("equals", Object.class, Object.class);
+        Method equals = test.getMethod("equals", valueClass, Object.class);
         boolean rc = (boolean)equals.invoke(null, value, value);
         if (!rc) {
             throw new RuntimeException("expected equals");
@@ -107,14 +104,6 @@
             return values().hashCode();
         }
 
-        public long longHashCode() {
-            long hash = 1;
-            for (Object o : values()) {
-                hash = 31 * hash + o.hashCode();
-            }
-            return hash;
-        }
-
         public String toString() {
             System.out.println(l);
             return String.format("[%s, %s, %s, %s, %s]", Value.class.asValueType(),
@@ -127,7 +116,7 @@
      */
     private static Class<?> valueTestClass() throws Exception {
         Path path = Paths.get(TEST_CLASSES, "ValueTest.class");
-        generate(Value.class, "ValueTest", path);
+        generate(Value.class.asValueType(), "ValueTest", path);
         return Class.forName("ValueTest");
     }
 
@@ -137,7 +126,7 @@
         }
     }
 
-    static final int CLASSFILE_VERSION = 55;
+    static final int CLASSFILE_VERSION = 56;
     static void generate(Class<?> c, String className, Path path) throws IOException {
         ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
 
@@ -159,7 +148,7 @@
         MethodVisitor mv = cw.visitMethod(
             ACC_PUBLIC + ACC_STATIC + ACC_FINAL,
             "hashCode",
-            "(Ljava/lang/Object;)I",
+            Type.getMethodDescriptor(Type.INT_TYPE, type),
             null,
             null);
 
@@ -173,29 +162,15 @@
 
         mv = cw.visitMethod(
             ACC_PUBLIC + ACC_STATIC + ACC_FINAL,
-            "longHashCode",
-            "(Ljava/lang/Object;)J",
-            null,
-            null);
-
-        mv.visitVarInsn(ALOAD, 0);
-        mv.visitInvokeDynamicInsn("longHashCode", "(Ljava/lang/Object;)J",
-            bootstrap, type);
-        mv.visitInsn(LRETURN);
-
-        mv.visitMaxs(-1, -1);
-        mv.visitEnd();
-
-        mv = cw.visitMethod(
-            ACC_PUBLIC + ACC_STATIC + ACC_FINAL,
             "equals",
-            "(Ljava/lang/Object;Ljava/lang/Object;)Z",
+            Type.getMethodDescriptor(Type.BOOLEAN_TYPE, type, Type.getType(Object.class)),
             null,
             null);
 
         mv.visitVarInsn(ALOAD, 0);
         mv.visitVarInsn(ALOAD, 1);
-        mv.visitInvokeDynamicInsn("equals", "(Ljava/lang/Object;Ljava/lang/Object;)Z",
+        mv.visitInvokeDynamicInsn("equals",
+            Type.getMethodDescriptor(Type.BOOLEAN_TYPE, type, Type.getType(Object.class)),
             bootstrap, type);
         mv.visitInsn(IRETURN);
         mv.visitMaxs(-1, -1);
@@ -204,12 +179,13 @@
         mv = cw.visitMethod(
             ACC_PUBLIC + ACC_STATIC + ACC_FINAL,
             "toString",
-            "(Ljava/lang/Object;)Ljava/lang/String;",
+            Type.getMethodDescriptor(Type.getType(String.class), type),
             null,
             null);
 
         mv.visitVarInsn(ALOAD, 0);
-        mv.visitInvokeDynamicInsn("toString", "(Ljava/lang/Object;)Ljava/lang/String;",
+        mv.visitInvokeDynamicInsn("toString",
+            Type.getMethodDescriptor(Type.getType(String.class), type),
             bootstrap,  type);
         mv.visitInsn(ARETURN);
         mv.visitMaxs(-1, -1);
--- a/test/langtools/tools/javac/valhalla/lworld-values/BoxValCastTest.java	Wed Dec 12 10:07:38 2018 -0800
+++ b/test/langtools/tools/javac/valhalla/lworld-values/BoxValCastTest.java	Wed Dec 12 10:08:39 2018 -0800
@@ -67,27 +67,27 @@
         "   flags: (0x0008) ACC_STATIC",
         "   Code:",
         "     stack=1, locals=0, args_size=0",
-        "        0: invokestatic  #7                  // Method $makeValue$:()QBoxValCastTest$VT;",
-        "        3: checkcast     #8                  // class BoxValCastTest$VT",
-        "        6: putstatic     #9                  // Field vtbox:LBoxValCastTest$VT;",
-        "        9: getstatic     #9                  // Field vtbox:LBoxValCastTest$VT;",
+        "        0: invokestatic  #6                  // Method $makeValue$:()QBoxValCastTest$VT;",
+        "        3: checkcast     #7                  // class BoxValCastTest$VT",
+        "        6: putstatic     #8                  // Field vtbox:LBoxValCastTest$VT;",
+        "        9: getstatic     #8                  // Field vtbox:LBoxValCastTest$VT;",
         "       12: checkcast     #2                  // class \"QBoxValCastTest$VT;\"",
-        "       15: putstatic     #10                 // Field vtval:QBoxValCastTest$VT;",
-        "       18: getstatic     #9                  // Field vtbox:LBoxValCastTest$VT;",
+        "       15: putstatic     #9                  // Field vtval:QBoxValCastTest$VT;",
+        "       18: getstatic     #8                  // Field vtbox:LBoxValCastTest$VT;",
         "       21: checkcast     #2                  // class \"QBoxValCastTest$VT;\"",
-        "       24: putstatic     #11                 // Field vt:QBoxValCastTest$VT;",
-        "       27: getstatic     #10                 // Field vtval:QBoxValCastTest$VT;",
-        "       30: putstatic     #12                 // Field vtval2:QBoxValCastTest$VT;",
-        "       33: getstatic     #10                 // Field vtval:QBoxValCastTest$VT;",
-        "       36: checkcast     #8                  // class BoxValCastTest$VT",
-        "       39: putstatic     #13                 // Field box:LBoxValCastTest$VT;",
-        "       42: getstatic     #13                 // Field box:LBoxValCastTest$VT;",
-        "       45: putstatic     #14                 // Field box2:LBoxValCastTest$VT;",
-        "       48: invokestatic  #7                  // Method $makeValue$:()QBoxValCastTest$VT;",
-        "       51: checkcast     #8                  // class BoxValCastTest$VT",
-        "       54: invokestatic  #15                 // Method id:(LBoxValCastTest$VT;)QBoxValCastTest$VT;",
-        "       57: checkcast     #8                  // class BoxValCastTest$VT",
-        "       60: putstatic     #16                 // Field box3:LBoxValCastTest$VT;",
+        "       24: putstatic     #10                 // Field vt:QBoxValCastTest$VT;",
+        "       27: getstatic     #9                  // Field vtval:QBoxValCastTest$VT;",
+        "       30: putstatic     #11                 // Field vtval2:QBoxValCastTest$VT;",
+        "       33: getstatic     #9                  // Field vtval:QBoxValCastTest$VT;",
+        "       36: checkcast     #7                  // class BoxValCastTest$VT",
+        "       39: putstatic     #12                 // Field box:LBoxValCastTest$VT;",
+        "       42: getstatic     #12                 // Field box:LBoxValCastTest$VT;",
+        "       45: putstatic     #13                 // Field box2:LBoxValCastTest$VT;",
+        "       48: invokestatic  #6                  // Method $makeValue$:()QBoxValCastTest$VT;",
+        "       51: checkcast     #7                  // class BoxValCastTest$VT",
+        "       54: invokestatic  #14                 // Method id:(LBoxValCastTest$VT;)QBoxValCastTest$VT;",
+        "       57: checkcast     #7                  // class BoxValCastTest$VT",
+        "       60: putstatic     #15                 // Field box3:LBoxValCastTest$VT;",
         "       63: return",
            
          });
--- a/test/langtools/tools/javac/valhalla/lworld-values/QTypeTest.java	Wed Dec 12 10:07:38 2018 -0800
+++ b/test/langtools/tools/javac/valhalla/lworld-values/QTypeTest.java	Wed Dec 12 10:08:39 2018 -0800
@@ -48,27 +48,26 @@
         runCheck(params, new String [] {
               "final value class QTypedValue",
               "  flags: (0x0130) ACC_FINAL, ACC_SUPER, ACC_VALUE",
-              "  this_class: #8                          // QTypedValue",
-              "   #8 = Class              #50            // QTypedValue",
-              "   #9 = Class              #51            // \"QQTypedValue;\"",
-              "  #10 = Fieldref           #8.#52         // QTypedValue.f1:[QQTypedValue;",
-              "  #11 = Fieldref           #8.#53         // QTypedValue.f2:[QQTypedValue;",
-              "  #12 = Class              #20            // \"[[[QQTypedValue;\"",
-              "  #13 = Fieldref           #8.#54         // QTypedValue.f3:[[[QQTypedValue;",
-              "  #14 = Fieldref           #8.#55         // QTypedValue.f4:[[[QQTypedValue;",
-              "  #17 = Utf8               [QQTypedValue;",
-              "  #20 = Utf8               [[[QQTypedValue;",
-              "  #27 = Utf8               (QQTypedValue;I)V",
-              "  #38 = Utf8               ()QQTypedValue;",
-              "  #42 = NameAndType        #37:#38        // $makeValue$:()QQTypedValue;",
-              "  #43 = NameAndType        #26:#27        // foo:(QQTypedValue;I)V",
-              "  #50 = Utf8               QTypedValue",
-              "  #51 = Utf8               QQTypedValue;",
-              "  #52 = NameAndType        #16:#17        // f1:[QQTypedValue;",
-              "  #53 = NameAndType        #18:#17        // f2:[QQTypedValue;",
-              "  #54 = NameAndType        #19:#20        // f3:[[[QQTypedValue;",
-              "  #55 = NameAndType        #21:#20        // f4:[[[QQTypedValue;",
-              "  final QTypedValue[] f1;",
+              "  this_class: #7                          // QTypedValue",
+              "   #7 = Class              #46            // QTypedValue",
+              "   #8 = Class              #47            // \"QQTypedValue;\"",
+              "   #9 = Fieldref           #7.#48         // QTypedValue.f1:[QQTypedValue;",
+              "  #10 = Fieldref           #7.#49         // QTypedValue.f2:[QQTypedValue;",
+              "  #11 = Class              #19            // \"[[[QQTypedValue;\"",
+              "  #12 = Fieldref           #7.#50         // QTypedValue.f3:[[[QQTypedValue;",
+              "  #13 = Fieldref           #7.#51         // QTypedValue.f4:[[[QQTypedValue;",
+              "  #16 = Utf8               [QQTypedValue;",
+              "  #19 = Utf8               [[[QQTypedValue;",
+              "  #26 = Utf8               (QQTypedValue;I)V",
+              "  #39 = NameAndType        #34:#35        // $makeValue$:()QQTypedValue;",
+              "  #40 = NameAndType        #25:#26        // foo:(QQTypedValue;I)V",
+              "  #46 = Utf8               QTypedValue",
+              "  #47 = Utf8               QQTypedValue;",
+              "  #48 = NameAndType        #15:#16        // f1:[QQTypedValue;",
+              "  #49 = NameAndType        #17:#16        // f2:[QQTypedValue;",
+              "  #50 = NameAndType        #18:#19        // f3:[[[QQTypedValue;",
+              "  #51 = NameAndType        #20:#19        // f4:[[[QQTypedValue;",
+              " final QTypedValue[] f1;",
               "    descriptor: [QQTypedValue;",
               "    flags: (0x0010) ACC_FINAL",
               "  final QTypedValue[] f2;",
@@ -111,38 +110,39 @@
               "        frame_type = 255 /* full_frame */",
               "          offset_delta = 4",
               "          locals = [ class \"QQTypedValue;\", class \"QQTypedValue;\", int ]",
+              "          stack = []",
               "static QTypedValue $makeValue$();",
               "    descriptor: ()QQTypedValue;",
               "    flags: (0x1008) ACC_STATIC, ACC_SYNTHETIC",
               "    Code:",
               "      stack=2, locals=1, args_size=0",
-              "         0: defaultvalue  #8                  // class QTypedValue",
+              "         0: defaultvalue  #7                  // class QTypedValue",
               "         3: astore_0",
               "         4: bipush        10",
-              "         6: anewarray     #9                  // class \"QQTypedValue;\"",
+              "         6: anewarray     #8                  // class \"QQTypedValue;\"",
               "         9: aload_0",
               "        10: swap",
-              "        11: withfield     #10                 // Field f1:[QQTypedValue;",
+              "        11: withfield     #9                  // Field f1:[QQTypedValue;",
               "        14: astore_0",
               "        15: bipush        10",
-              "        17: anewarray     #9                  // class \"QQTypedValue;\"",
+              "        17: anewarray     #8                  // class \"QQTypedValue;\"",
               "        20: aload_0",
               "        21: swap",
-              "        22: withfield     #11                 // Field f2:[QQTypedValue;",
+              "        22: withfield     #10                 // Field f2:[QQTypedValue;",
               "        25: astore_0",
               "        26: bipush        10",
               "        28: bipush        10",
-              "        30: multianewarray #12,  2            // class \"[[[QQTypedValue;\"",
+              "        30: multianewarray #11,  2            // class \"[[[QQTypedValue;\"",
               "        34: aload_0",
               "        35: swap",
-              "        36: withfield     #13                 // Field f3:[[[QQTypedValue;",
+              "        36: withfield     #12                 // Field f3:[[[QQTypedValue;",
               "        39: astore_0",
               "        40: bipush        10",
               "        42: bipush        10",
-              "        44: multianewarray #12,  2            // class \"[[[QQTypedValue;\"",
+              "        44: multianewarray #11,  2            // class \"[[[QQTypedValue;\"",
               "        48: aload_0",
               "        49: swap",
-              "        50: withfield     #14                 // Field f4:[[[QQTypedValue;",
+              "        50: withfield     #13                 // Field f4:[[[QQTypedValue;",
               "        53: astore_0",
               "        54: aload_0",
               "        55: areturn",
--- a/test/langtools/tools/javac/valhalla/lworld-values/ValueBootstrapMethodsTest.java	Wed Dec 12 10:07:38 2018 -0800
+++ b/test/langtools/tools/javac/valhalla/lworld-values/ValueBootstrapMethodsTest.java	Wed Dec 12 10:08:39 2018 -0800
@@ -62,14 +62,6 @@
             return values().hashCode();
         }
 
-        public long localLongHashCode() {
-            long hash = 1;
-            for (Object o : values()) {
-                hash = 31 * hash + o.hashCode();
-            }
-            return hash;
-        }
-
         public String localToString() {
             System.out.println(l);
             return String.format("[%s, %s, %s, %s, %s]", Value.class.asValueType(),
@@ -88,7 +80,6 @@
         Value value = Value.make(10, 5.03, "foo", "bar", "goo");
 
         assertEquals(value.localHashCode(), value.hashCode());
-        assertEquals(value.localLongHashCode(), value.longHashCode());
         assertEquals(value.localToString(), value.toString());
 
         if (!value.equals(value)) {