--- old/src/java.base/share/classes/java/lang/Class.java 2019-06-03 14:39:17.769929700 -0400 +++ new/src/java.base/share/classes/java/lang/Class.java 2019-06-03 14:39:17.365927696 -0400 @@ -631,11 +631,6 @@ public T newInstance() throws InstantiationException, IllegalAccessException { - if (this.isInlineClass()) { - throw new IllegalAccessException( - "cannot create new instance of an inline class " + this.getName()); - } - SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), false); --- old/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java 2019-06-03 14:39:18.941935511 -0400 +++ new/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java 2019-06-03 14:39:18.533933488 -0400 @@ -298,10 +298,8 @@ modifiers = ((Field) this).getModifiers(); } - // does not allow to suppress access check for Value class's - // constructor or field + // Do not allow suppression of access check for inline class's field if (declaringClass.isInlineClass()) { - if (this instanceof Constructor) return false; if (this instanceof Field && Modifier.isFinal(modifiers)) return false; } --- old/src/java.base/share/classes/java/lang/reflect/Constructor.java 2019-06-03 14:39:20.061941065 -0400 +++ new/src/java.base/share/classes/java/lang/reflect/Constructor.java 2019-06-03 14:39:19.657939062 -0400 @@ -180,10 +180,6 @@ AccessibleObject.checkPermission(); if (flag) { - if (clazz.isInlineClass()) { - throw new InaccessibleObjectException( - "Unable to make an inline class constructor \"" + this + "\" accessible"); - } checkCanSetAccessible(Reflection.getCallerClass()); } setAccessible0(flag); @@ -482,10 +478,6 @@ throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { - if (clazz.isInlineClass()) { - throw new IllegalAccessException( - "cannot create new instance of an inline class " + clazz.getName()); - } Class caller = override ? null : Reflection.getCallerClass(); return newInstanceWithCaller(initargs, !override, caller); } --- old/test/jdk/valhalla/valuetypes/Reflection.java 2019-06-03 14:39:21.209946758 -0400 +++ new/test/jdk/valhalla/valuetypes/Reflection.java 2019-06-03 14:39:20.801944735 -0400 @@ -29,9 +29,11 @@ * @run main/othervm -XX:+EnableValhalla Reflection */ -import java.lang.reflect.*; -import java.util.Arrays; -import java.util.stream.Collectors; +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InaccessibleObjectException; +import java.lang.reflect.Method; public class Reflection { public static void main(String... args) throws Exception { @@ -48,8 +50,6 @@ test.newInstance(); test.constructor(); test.accessFieldX(o.x); - test.setAccessible(); - test.trySetAccessible(); test.staticField(); } @@ -173,40 +173,15 @@ } catch (IllegalAccessException e) {} } + @SuppressWarnings("deprecation") void newInstance() throws Exception { - try { - Object o = c.newInstance(); - throw new RuntimeException("newInstance expected to be unsupported on inline class"); - } catch (IllegalAccessException e) {} + Object o = c.newInstance(); + assertEquals(o.getClass(), c); } void constructor() throws Exception { - try { - ctor.newInstance(); - throw new RuntimeException("IllegalAccessException not thrown"); - } catch (IllegalAccessException e) { } - } - - void setAccessible() throws Exception { - try { - ctor.setAccessible(true); - throw new RuntimeException("InaccessibleObjectException not thrown"); - } catch (InaccessibleObjectException e) { e.printStackTrace(); } - Field field = c.getField("x"); - try { - field.setAccessible(true); - throw new RuntimeException("InaccessibleObjectException not thrown"); - } catch (InaccessibleObjectException e) { e.printStackTrace(); } - } - - void trySetAccessible() throws Exception { - if (ctor.trySetAccessible()) { - throw new RuntimeException("trySetAccessible should not succeed"); - } - Field field = c.getField("x"); - if (field.trySetAccessible()) { - throw new RuntimeException("trySetAccessible should not succeed"); - } + Object o = ctor.newInstance(); + assertEquals(o.getClass(), c); } void staticField() throws Exception { --- /dev/null 2019-05-28 09:59:29.644075095 -0400 +++ new/test/jdk/valhalla/valuetypes/InlineConstructorTest.java 2019-06-03 14:39:21.961950487 -0400 @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2019, 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 Test reflection of constructors for inline classes + * @run main/othervm -XX:+EnableValhalla InlineConstructorTest + */ + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InaccessibleObjectException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + +public class InlineConstructorTest { + + // Target test class + static inline class SimpleInline { + public final int x; + + SimpleInline() { + x = -1; + } + + public SimpleInline(int x) { + this.x = x; + } + } + + private final Class c; + + public static void main(String... args) throws Exception { + testSimpleInlineClass(); + } + + static void testSimpleInlineClass() throws Exception { + InlineConstructorTest test = new InlineConstructorTest(SimpleInline.class); + test.constructor(); + test.constructors("public InlineConstructorTest$SimpleInline(int)", + "InlineConstructorTest$SimpleInline()"); + test.setAccessible(); + test.trySetAccessible(); + test.initFactoryNotMethods(); + } + + InlineConstructorTest(Class type) throws Exception { + String cn = type.getName(); + this.c = Class.forName(cn); + + assertTrue(c.isInlineClass()); + assertEquals(c, type); + } + + void constructor() throws Exception { + Constructor ctor = c.getDeclaredConstructor(); + Object o = ctor.newInstance(); + assertEquals(o.getClass(), c); + } + + // Check that the class has the expected Constructors + void constructors(String... expected) throws Exception { + Constructor[] cons = c.getDeclaredConstructors(); + Set actualSig = + Arrays.stream(cons).map(Constructor::toString).collect(Collectors.toSet()); + Set expectedSig = Set.of(expected); + boolean ok = expectedSig.equals(actualSig); + if (!ok) { + System.out.printf("expected: %s%n", expectedSig); + System.out.printf("declared: %s%n", actualSig); + assertTrue(ok); + } + } + + // Check that the constructor can be set accessible and that the field x can not + void setAccessible() throws Exception { + Constructor ctor = c.getDeclaredConstructor(); + ctor.setAccessible(true); + Field field = c.getField("x"); + try { + field.setAccessible(true); + throw new RuntimeException("InaccessibleObjectException not thrown"); + } catch (InaccessibleObjectException e) { + // IOE is expected + } + } + + // Check that the constructor can be set accessible and that the field x can not + void trySetAccessible() throws Exception { + Constructor ctor = c.getDeclaredConstructor(); + assertTrue(ctor.trySetAccessible()); + Field field = c.getField("x"); + if (field.trySetAccessible()) { + throw new RuntimeException("trySetAccessible should not succeed"); + } + } + + // Check that the class does not have a static method with the name + void initFactoryNotMethods() { + Method[] methods = c.getDeclaredMethods(); + for (Method m : methods) { + if (Modifier.isStatic(m.getModifiers())) { + assertFalse(m.getName().equals("")); + } + } + } + + static void assertEquals(Object o1, Object o2) { + if (o1 == o2 || o1.equals(o2)) + return; + + throw new AssertionError(o1 + " != " + o2); + } + + static void assertTrue(boolean value) { + if (!value) + throw new AssertionError("expected true"); + } + + static void assertFalse(boolean value) { + if (value) + throw new AssertionError("expected false"); + } +}