--- old/src/java.base/share/classes/java/lang/Class.java 2017-06-20 14:47:33.000000000 -0700 +++ new/src/java.base/share/classes/java/lang/Class.java 2017-06-20 14:47:33.000000000 -0700 @@ -288,7 +288,11 @@ public static Class forName(String className) throws ClassNotFoundException { Class caller = Reflection.getCallerClass(); - return forName0(className, true, ClassLoader.getClassLoader(caller), caller); + Class c = forName0(className, true, ClassLoader.getClassLoader(caller), caller); + if (c.isValueClass()) { + throw new ClassNotFoundException(className + " is a derived value class"); + } + return c; } @@ -371,13 +375,17 @@ } } } - return forName0(name, initialize, loader, caller); + Class c = forName0(name, initialize, loader, caller); + if (c.isValueClass()) { + throw new ClassNotFoundException(name + " is a derived value class"); + } + return c; } /** Called after security check for system loader access checks have been made. */ - private static native Class forName0(String name, boolean initialize, - ClassLoader loader, - Class caller) + static native Class forName0(String name, boolean initialize, + ClassLoader loader, + Class caller) throws ClassNotFoundException; @@ -443,10 +451,32 @@ PrivilegedAction pa = module::getClassLoader; ClassLoader cl = AccessController.doPrivileged(pa); + Class c; if (cl != null) { - return cl.loadClass(module, name); + c = cl.loadClass(module, name); } else { - return BootLoader.loadClass(module, name); + c = BootLoader.loadClass(module, name); + } + + return c != null && !c.isValueClass() ? c : null; + } + + private boolean isValueClass() { + Class c = this; + while (c.isArray()) { + c = c.getComponentType(); + } + + // This could call MinimalValueTypes_1_0::isValueType or check ACC_VALUE. + // For now, check if it is a subtype of __Value to avoid + // initializing MinimalValueTypes_1_0 class during early startup. + return __Value.class.isAssignableFrom(c) && c != __Value.class; + } + + private void ensureNotValueClass() { + if (this.isValueClass()) { + throw new UnsupportedOperationException("cannot reflect on derived value type " + + this.getName()); } } @@ -508,6 +538,8 @@ public T newInstance() throws InstantiationException, IllegalAccessException { + ensureNotValueClass(); + SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), false); @@ -1237,6 +1269,8 @@ // Perform access check final Class enclosingCandidate = enclosingInfo.getEnclosingClass(); + enclosingCandidate.ensureNotValueClass(); + SecurityManager sm = System.getSecurityManager(); if (sm != null) { enclosingCandidate.checkMemberAccess(sm, Member.DECLARED, @@ -1393,6 +1427,8 @@ // Perform access check final Class enclosingCandidate = enclosingInfo.getEnclosingClass(); + enclosingCandidate.ensureNotValueClass(); + SecurityManager sm = System.getSecurityManager(); if (sm != null) { enclosingCandidate.checkMemberAccess(sm, Member.DECLARED, @@ -1689,6 +1725,8 @@ */ @CallerSensitive public Class[] getClasses() { + ensureNotValueClass(); + SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), false); @@ -1758,6 +1796,8 @@ */ @CallerSensitive public Field[] getFields() throws SecurityException { + ensureNotValueClass(); + SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), true); @@ -1848,6 +1888,8 @@ */ @CallerSensitive public Method[] getMethods() throws SecurityException { + ensureNotValueClass(); + SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), true); @@ -1887,6 +1929,8 @@ */ @CallerSensitive public Constructor[] getConstructors() throws SecurityException { + ensureNotValueClass(); + SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), true); @@ -1940,6 +1984,8 @@ @CallerSensitive public Field getField(String name) throws NoSuchFieldException, SecurityException { + ensureNotValueClass(); + Objects.requireNonNull(name); SecurityManager sm = System.getSecurityManager(); if (sm != null) { @@ -2049,6 +2095,8 @@ @CallerSensitive public Method getMethod(String name, Class... parameterTypes) throws NoSuchMethodException, SecurityException { + ensureNotValueClass(); + Objects.requireNonNull(name); SecurityManager sm = System.getSecurityManager(); if (sm != null) { @@ -2113,6 +2161,8 @@ public Constructor getConstructor(Class... parameterTypes) throws NoSuchMethodException, SecurityException { + ensureNotValueClass(); + SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), true); @@ -2159,6 +2209,8 @@ */ @CallerSensitive public Class[] getDeclaredClasses() throws SecurityException { + ensureNotValueClass(); + SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), false); @@ -2211,6 +2263,8 @@ */ @CallerSensitive public Field[] getDeclaredFields() throws SecurityException { + ensureNotValueClass(); + SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true); @@ -2273,6 +2327,8 @@ */ @CallerSensitive public Method[] getDeclaredMethods() throws SecurityException { + ensureNotValueClass(); + SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true); @@ -2321,6 +2377,8 @@ */ @CallerSensitive public Constructor[] getDeclaredConstructors() throws SecurityException { + ensureNotValueClass(); + SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true); @@ -2372,6 +2430,8 @@ @CallerSensitive public Field getDeclaredField(String name) throws NoSuchFieldException, SecurityException { + ensureNotValueClass(); + Objects.requireNonNull(name); SecurityManager sm = System.getSecurityManager(); if (sm != null) { @@ -2436,6 +2496,8 @@ @CallerSensitive public Method getDeclaredMethod(String name, Class... parameterTypes) throws NoSuchMethodException, SecurityException { + ensureNotValueClass(); + Objects.requireNonNull(name); SecurityManager sm = System.getSecurityManager(); if (sm != null) { @@ -2491,6 +2553,8 @@ public Constructor getDeclaredConstructor(Class... parameterTypes) throws NoSuchMethodException, SecurityException { + ensureNotValueClass(); + SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true); --- old/src/java.base/share/classes/java/lang/System.java 2017-06-20 14:47:34.000000000 -0700 +++ new/src/java.base/share/classes/java/lang/System.java 2017-06-20 14:47:34.000000000 -0700 @@ -56,6 +56,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; +import jdk.internal.loader.BootLoader; import jdk.internal.module.ModuleBootstrap; import jdk.internal.module.ServicesCatalog; import jdk.internal.reflect.CallerSensitive; @@ -2165,6 +2166,14 @@ public Stream layers(ClassLoader loader) { return ModuleLayer.layers(loader); } + public Class loadValueTypeClass(Module module, ClassLoader cl, String name) { + try { + // VM support to define DVT + return Class.forName0(name, false, cl, Object.class); + } catch (ClassNotFoundException e) { + throw new InternalError(e); + } + } }); } } --- old/src/java.base/share/classes/jdk/experimental/value/ValueType.java 2017-06-20 14:47:35.000000000 -0700 +++ new/src/java.base/share/classes/jdk/experimental/value/ValueType.java 2017-06-20 14:47:34.000000000 -0700 @@ -183,15 +183,12 @@ } public Class arrayValueClass(int dims) { - try { - String dimsStr = "[[[[[[[[[[[[[[[["; - if (dims < 1 || dims > 16) { - throw new IllegalArgumentException("cannot create array class for dimension > 16"); - } - return Class.forName(dimsStr.substring(0, dims) + "Q" + valueClass().getName() + ";", false, boxLookup.lookupClass().getClassLoader()); - } catch (ClassNotFoundException ex) { - throw new IllegalStateException(ex); + String dimsStr = "[[[[[[[[[[[[[[[["; + if (dims < 1 || dims > 16) { + throw new IllegalArgumentException("cannot create array class for dimension > 16"); } + String cn = dimsStr.substring(0, dims) + "Q" + valueClass().getName() + ";"; + return MinimalValueTypes_1_0.loadValueTypeClass(boxLookup.lookupClass(), cn); } public String toString() { --- old/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java 2017-06-20 14:47:35.000000000 -0700 +++ new/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java 2017-06-20 14:47:35.000000000 -0700 @@ -248,4 +248,9 @@ * given class loader. */ Stream layers(ClassLoader loader); + + /** + * Loads a derived ValueType class + */ + Class loadValueTypeClass(Module module, ClassLoader loader, String name); } --- old/src/java.base/share/classes/valhalla/shady/MinimalValueTypes_1_0.java 2017-06-20 14:47:36.000000000 -0700 +++ new/src/java.base/share/classes/valhalla/shady/MinimalValueTypes_1_0.java 2017-06-20 14:47:36.000000000 -0700 @@ -28,32 +28,40 @@ import jdk.internal.misc.Unsafe; import sun.security.action.GetPropertyAction; -import java.io.File; -import java.io.FileOutputStream; +import java.io.BufferedOutputStream; import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.security.ProtectionDomain; import java.util.Properties; import static jdk.internal.org.objectweb.asm.Opcodes.*; +import jdk.internal.misc.JavaLangAccess; +import jdk.internal.misc.SharedSecrets; public class MinimalValueTypes_1_0 { - public static final int V53_1 = 1 << 16 | 53; - public static final int ACC_VALUE = ACC_NATIVE; - public static final String OBJECT_CLASS_DESC = "java/lang/Object"; - public static final String VALUE_CLASS_DESC = "java/lang/__Value"; + public static final int V53_1 = 1 << 16 | 53; + public static final int ACC_VALUE = ACC_NATIVE; + public static final String OBJECT_CLASS_DESC = "java/lang/Object"; + public static final String VALUE_CLASS_DESC = "java/lang/__Value"; 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 final boolean DUMP_CLASS_FILES; + private static final JavaLangAccess JLA; static { // 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")); + props.getProperty("java.lang.invoke.MethodHandle.DUMP_CLASS_FILES")); + + JLA = SharedSecrets.getJavaLangAccess(); } public static String getValueTypeClassName(ValueTypeDesc valueTypeDesc) { @@ -79,11 +87,11 @@ return Class.forName(getValueCapableClassName(x.getName()), true, x.getClassLoader()); } - public static Class getValueTypeClass(Class x) throws ClassNotFoundException { + public static Class getValueTypeClass(Class x) throws ClassNotFoundException { if (isValueType(x)) { throw new IllegalArgumentException("Expected Value Capable Class"); } - return Class.forName(getValueTypeClassName(x.getName()), true, x.getClassLoader()); + return loadValueTypeClass(x, getValueTypeClassName(x.getName())); } public static String getValueTypeClassName(Class x) { @@ -98,18 +106,27 @@ if (x.getDeclaredAnnotation(jvm.internal.value.DeriveValueType.class) == null) { return false; } - try { - Class.forName(getValueTypeClassName(x), true, x.getClassLoader()); - return true; + return loadValueTypeClass(x, getValueTypeClassName(x)) != null; + } + + public static Class loadValueTypeClass(Class vcc, String className) { + if (isValueType(vcc)) { + throw new IllegalArgumentException(vcc.getName() + " already a derived value type"); } - catch (ClassNotFoundException cnfe) { - return false; + Class c = JLA.loadValueTypeClass(vcc.getModule(), vcc.getClassLoader(), className); + if (c == null) { + throw new InternalError(className + " not loaded"); } + return c; } // fds : name/sig pairs // fmods : field modifiers - public static String createDerivedValueType(String vccInternalClassName, ClassLoader cl, ProtectionDomain pd, String[] fds, int[] fmods) { + public static String createDerivedValueType(String vccInternalClassName, + ClassLoader cl, + ProtectionDomain pd, + String[] fds, + int[] fmods) { String vtInternalClassName = getValueTypeClassName(vccInternalClassName); ValueTypeDesc valueTypeDesc = new ValueTypeDesc(vccInternalClassName, fds, fmods); byte[] valueTypeBytes = createValueType(valueTypeDesc); @@ -122,8 +139,8 @@ String valueTypeClassName = getValueTypeClassName(valueTypeDesc); BasicClassBuilder builder = new BasicClassBuilder(valueTypeClassName, 53, 1) - .withFlags(DERIVE_VT_CLASS_ACCESS) - .withSuperclass(VALUE_CLASS_DESC); + .withFlags(DERIVE_VT_CLASS_ACCESS) + .withSuperclass(VALUE_CLASS_DESC); ValueTypeDesc.Field[] fields = valueTypeDesc.getFields(); for (ValueTypeDesc.Field field : fields) { @@ -136,15 +153,13 @@ } /** debugging flag for saving generated class files */ - private static final File DUMP_CLASS_FILES_DIR; + private static final Path DUMP_CLASS_FILES_DIR; static { if (DUMP_CLASS_FILES) { try { - File dumpDir = new File("DUMP_CLASS_FILES"); - if (!dumpDir.exists()) { - dumpDir.mkdirs(); - } + Path dumpDir = Paths.get("DUMP_CLASS_FILES"); + Files.createDirectories(dumpDir); DUMP_CLASS_FILES_DIR = dumpDir; } catch (Exception e) { throw new InternalError(e); @@ -155,25 +170,24 @@ } public static void maybeDump(final String className, final byte[] classFile) { - if (DUMP_CLASS_FILES) { + if (DUMP_CLASS_FILES_DIR != null) { java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction<>() { - public Void run() { - try { - 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 InternalError(ex); - } + new java.security.PrivilegedAction<>() { + public Void run() { + String dumpName = className; + //dumpName = dumpName.replace('/', '-'); + Path dumpFile = DUMP_CLASS_FILES_DIR.resolve(dumpName + ".class"); + System.out.println("dump: " + dumpFile); + try (OutputStream os = Files.newOutputStream(dumpFile); + BufferedOutputStream bos = new BufferedOutputStream(os)) { + bos.write(classFile); + } catch (IOException ex) { + throw new InternalError(ex); } - }); + return null; + } + }); + } } --- old/test/valhalla/mvt/MVTAccessCheck.java 2017-06-20 14:47:37.000000000 -0700 +++ new/test/valhalla/mvt/MVTAccessCheck.java 2017-06-20 14:47:37.000000000 -0700 @@ -4,9 +4,7 @@ * * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. + * 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 --- old/test/valhalla/mvt/MVTTest.java 2017-06-20 14:47:38.000000000 -0700 +++ new/test/valhalla/mvt/MVTTest.java 2017-06-20 14:47:37.000000000 -0700 @@ -4,9 +4,7 @@ * * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. + * 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 --- /dev/null 2017-06-20 14:47:38.000000000 -0700 +++ new/test/valhalla/mvt/MVTReflectionTest.java 2017-06-20 14:47:38.000000000 -0700 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2017, 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 basic test for reflection on MVT + * @build Point + * @run testng/othervm -Xint -Xverify:none -XX:+EnableMVT MVTReflectionTest + */ + +import jdk.experimental.value.ValueType; + +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +@Test +public class MVTReflectionTest { + private static Class VCC = Point.class; + private static ValueType VT = ValueType.forClass(VCC); + private static Class DVT = VT.valueClass(); + + public void testValueCapableClass() throws Exception { + Class pointClass = Class.forName("Point"); + assertEquals(pointClass, VCC); + + // test getSuperClass + assertEquals(pointClass.getSuperclass(), Object.class); + + // test getFields and getDeclaredFields + assertTrue(pointClass.getFields().length == 3); + assertTrue(pointClass.getDeclaredFields().length == 3); + } + + public void testDerivedValueType() throws Exception { + // test Class.forName + try { + Class c = Class.forName(DVT.getName()); + throw new RuntimeException("should fail to load " + c); + } catch (ClassNotFoundException e) {} + + Module m = Point.class.getClassLoader().getUnnamedModule(); + Class c = Class.forName(m, DVT.getName()); + assertEquals(c, null); + + // test getSuperClass + assertEquals(DVT.getSuperclass(), __Value.class); + + // test getFields and getDeclaredFields + try { + DVT.getFields(); + throw new RuntimeException("should fail to getFields on " + DVT); + } catch (UnsupportedOperationException e) {} + + try { + DVT.newInstance(); + throw new RuntimeException("should fail to newInstance on " + DVT); + } catch (UnsupportedOperationException e) {} + } + + public void testValueTypeArray() throws Exception { + Point[] points = new Point[0]; + + Class c1 = Class.forName("[LPoint;"); + Class c2 = VT.arrayValueClass(); + assertEquals(c1, points.getClass()); + + String name = "[Q" + DVT.getName() + ";"; + assertEquals(name, c2.getName()); + + // cannot load an array DVT class + try { + Class.forName(name); + throw new RuntimeException("should fail to load " + name); + } catch (ClassNotFoundException e) {} + } +} --- /dev/null 2017-06-20 14:47:39.000000000 -0700 +++ new/test/valhalla/mvt/modules/Driver.java 2017-06-20 14:47:39.000000000 -0700 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017, 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 basic test for MVT in modules + * @build m/* Driver + * @run main/othervm -Xint -Xverify:none -XX:+EnableMVT m/p.Main + */ + --- /dev/null 2017-06-20 14:47:39.000000000 -0700 +++ new/test/valhalla/mvt/modules/m/module-info.java 2017-06-20 14:47:39.000000000 -0700 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017, 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. + */ + +module m { + exports p; +} --- /dev/null 2017-06-20 14:47:40.000000000 -0700 +++ new/test/valhalla/mvt/modules/m/p/Main.java 2017-06-20 14:47:40.000000000 -0700 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2017, 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. + */ + +package p; + +import java.lang.invoke.*; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +import jdk.experimental.value.ValueType; +import p.internal.Point; + +public class Main { + private static List FIELD_NAMES = List.of("x", "y", "z"); + private static List> FIELD_TYPES = List.of(int.class, short.class, short.class); + + public static void main(String... args) throws Exception { + ValueType valueType = ValueType.forClass(Point.class); + Module module = Point.class.getModule(); + assertTrue(module.isNamed(), "unexpected " + module.toString()); + assertTrue(valueType.boxClass().getModule() == module, + "unexpected " + valueType.boxClass().getModule()); + assertTrue(valueType.valueClass().getModule() == module, + "unexpected " + valueType.valueClass().getModule() ); + + Field[] fields = Point.class.getDeclaredFields(); + assertTrue(fields.length == FIELD_NAMES.size(), Arrays.toString(fields)); + + // validate field names + List names = Arrays.stream(fields) + .sorted(Comparator.comparing(Field::getName)) + .map(Field::getName) + .collect(Collectors.toList()); + assertTrue(names.equals(FIELD_NAMES), names.toString()); + + // validate field types + List> types = Arrays.stream(fields) + .sorted(Comparator.comparing(Field::getName)) + .map(Field::getType) + .collect(Collectors.toList()); + assertTrue(types.equals(FIELD_TYPES), types.toString()); + + // getting MethodHandle + MethodHandles.Lookup lookup = + MethodHandles.privateLookupIn(Point.class, MethodHandles.lookup()); + for (Field f : fields) { + MethodHandle mh1 = valueType.findGetter(lookup, f.getName(), f.getType()); + MethodHandle mh2 = valueType.findWither(lookup, f.getName(), f.getType()); + System.out.println(mh1 + " " + mh2); + } + } + + private static void assertTrue(boolean b, String msg) { + if (!b) { + throw new RuntimeException(msg); + } + } +} --- /dev/null 2017-06-20 14:47:41.000000000 -0700 +++ new/test/valhalla/mvt/modules/m/p/internal/Point.java 2017-06-20 14:47:40.000000000 -0700 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2017, 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. + */ + +package p.internal; + +import java.util.Objects; + +@jvm.internal.value.DeriveValueType +public final class Point { + private final int x; + private final short y; + private final short z; + + Point(int x, short y, short z) { + this.x = x; + this.y = y; + this.z = z; + } + + @Override + public boolean equals(Object o) { + if (o instanceof Point) { + Point that = (Point) o; + return that.x == x && + that.y == y && + that.z == z; + } else { + return false; + } + } + + @Override + public int hashCode() { + return Objects.hash(x, y, z); + } + + @Override + public String toString() { + return "Point{" + + "x=" + x + + ", y=" + y + + ", z=" + z + + '}'; + } +}