1 /* 2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package runtime.valhalla.valuetypes; 24 25 import jdk.incubator.mvt.ValueType; 26 import java.lang.reflect.Field; 27 import java.lang.reflect.InvocationTargetException; 28 import java.lang.reflect.Method; 29 import static java.lang.reflect.Modifier.*; 30 import java.net.URL; 31 import java.util.ArrayList; 32 import java.util.HashMap; 33 34 import jdk.experimental.bytecode.*; 35 36 import jdk.internal.org.objectweb.asm.*; 37 import static jdk.internal.org.objectweb.asm.Opcodes.*; 38 39 import static jdk.test.lib.Asserts.*; 40 41 /* 42 * @test DeriveValueTypeCreation 43 * @summary Derive Value Type creation test 44 * @library /test/lib 45 * @compile DeriveValueTypeCreation.java 46 * @modules java.base/jdk.experimental.bytecode 47 * java.base/jdk.internal.org.objectweb.asm 48 * jdk.incubator.mvt 49 * @build runtime.valhalla.valuetypes.ValueCapableClass 50 * @run main/othervm -Xint -XX:+EnableMVT runtime.valhalla.valuetypes.DeriveValueTypeCreation 51 * @run main/othervm -Xcomp -XX:+EnableMVT runtime.valhalla.valuetypes.DeriveValueTypeCreation 52 */ 53 public class DeriveValueTypeCreation { 54 55 public static final String VCC_CLASSNAME = "runtime.valhalla.valuetypes.ValueCapableClass"; 56 public static final String DVT_SUFFIX = "$Value"; 57 58 public static final int TEST_DEF_CLASS_ACCESS = ACC_SUPER | ACC_PUBLIC | ACC_FINAL; 59 public static final int TEST_DEF_FIELD_ACCESS = ACC_PUBLIC | ACC_FINAL; 60 public static final String OBJECT_CLASS_DESC = "java/lang/Object"; 61 62 public static void main(String[] args) { 63 DeriveValueTypeCreation test = new DeriveValueTypeCreation(); 64 test.run(); 65 } 66 67 public void run() { 68 loadAndRunTest(); 69 notValueCapableClasses(); 70 loadDvtFirst(); 71 } 72 73 void loadAndRunTest() { 74 Class<?> clazz = null; 75 try { 76 clazz = Class.forName(VCC_CLASSNAME, true, getClass().getClassLoader()); 77 clazz.getDeclaredMethod("test").invoke(null); 78 } 79 catch (ClassNotFoundException cnfe) { fail("VCC class missing", cnfe); } 80 catch (NoSuchMethodException nsme) { fail("VCC test method missing", nsme); } 81 catch (Throwable t) { fail("Failed to invoke VCC.test()", t); } 82 83 checkValueCapableClass(clazz); 84 } 85 86 void checkValueCapableClass(Class<?> clazz) { 87 if (!ValueType.classHasValueType(clazz)) { 88 fail("!classHasValueType: " + clazz); 89 } 90 91 ValueType<?> vt = ValueType.forClass(clazz); 92 if (vt == null) { 93 fail("ValueType.forClass failed"); 94 } 95 96 System.out.println("ValueType: " + vt); 97 98 if (vt.boxClass() != clazz) { 99 fail("ValueType.boxClass() failed"); 100 } 101 102 // DVT class matches our expectations for the current implementation... 103 Class<?> vtClass = vt.valueClass(); 104 if (!vtClass.getName().equals(clazz.getName() + DVT_SUFFIX)) { 105 fail("ValueType.valueClass() failed"); 106 } 107 if (!vtClass.getSuperclass().getName().equals("java.lang.__Value")) { 108 fail("ValueType.valueClass() isn't a Value Type class"); 109 } 110 111 // Exercise "Class.getSimpleName()", we've cause problems with it before 112 String sn = vtClass.getSimpleName(); 113 System.out.println("SimpleName: " + sn); 114 115 if (clazz.getClassLoader() != vtClass.getClassLoader()) { 116 fail("ClassLoader mismatch"); 117 } 118 if (clazz.getProtectionDomain() != vtClass.getProtectionDomain()) { 119 fail("ProtectionDomain mismatch"); 120 } 121 } 122 123 void notValueCapableClasses() { 124 // First a control test to check createTestVccClass is working 125 try { 126 Class<?> cls = createTestVccClass("Control_Case_is_a_VCC", TEST_DEF_CLASS_ACCESS, OBJECT_CLASS_DESC, "I", TEST_DEF_FIELD_ACCESS); 127 checkValueCapableClass(cls); 128 } 129 catch (Exception e) { 130 fail("Control test failed", e); 131 } 132 133 testFailCase("Not_a_final_class", ACC_SUPER | ACC_PUBLIC, OBJECT_CLASS_DESC, "I", TEST_DEF_FIELD_ACCESS, "not a final class"); 134 testFailCase("No_fields", TEST_DEF_CLASS_ACCESS, OBJECT_CLASS_DESC, null, TEST_DEF_FIELD_ACCESS, "has no instance fields"); 135 testFailCase("Not_final_field", TEST_DEF_CLASS_ACCESS, OBJECT_CLASS_DESC, "I", ACC_PUBLIC, "contains non-final instance field"); 136 testFailCase("Super_not_Object", TEST_DEF_CLASS_ACCESS, "java/lang/Throwable", "I", TEST_DEF_FIELD_ACCESS, "does not derive from Object"); 137 } 138 139 void testFailCase(String clsName, 140 int klassAccess, 141 String superKlass, 142 String fieldType, 143 int fieldAccess, 144 String errMsgRequired) { 145 try { 146 createTestVccClass(clsName, klassAccess, superKlass, fieldType, fieldAccess); 147 fail(clsName + " : failed to fail with Error"); 148 } 149 catch (ClassNotFoundException cnfe) { 150 fail(clsName + " : Unexpected ClassNotFoundException", cnfe); 151 } 152 catch (Error err) { 153 if (!err.getMessage().contains(errMsgRequired)) { 154 fail(clsName + " : Not the error we were looking for", err); 155 } 156 } 157 } 158 159 byte[] createTestVccClassBytes(String name, 160 boolean vccAnnotation) { 161 return createTestVccClassBytes(name, TEST_DEF_CLASS_ACCESS, vccAnnotation, OBJECT_CLASS_DESC, "I", TEST_DEF_FIELD_ACCESS); 162 } 163 164 byte[] createTestVccClassBytes(String name, 165 int klassAccess, 166 String superKlass, 167 String fieldType, 168 int fieldAccess) { 169 return createTestVccClassBytes(name, klassAccess, true, superKlass, fieldType, fieldAccess); 170 } 171 172 byte[] createTestVccClassBytes(String name, 173 int klassAccess, 174 boolean vccAnnotation, 175 String superKlass, 176 String fieldType, 177 int fieldAccess) { 178 ClassWriter cw = new ClassWriter(0); 179 cw.visit(52, klassAccess, name, null, superKlass, null); 180 if (vccAnnotation ) { 181 cw.visitAnnotation("Ljdk/incubator/mvt/ValueCapableClass;", true); 182 } 183 if (fieldType != null) { 184 cw.visitField(fieldAccess, "x", fieldType, null, null); 185 } 186 cw.visitEnd(); 187 return cw.toByteArray(); 188 } 189 190 Class<?> createTestVccClass(String name, 191 int klassAccess, 192 String superKlass, 193 String fieldType, 194 int fieldAccess) throws ClassNotFoundException { 195 return new TestClassLoader(name, 196 createTestVccClassBytes(name, klassAccess, superKlass, fieldType, fieldAccess)).loadClass(name); 197 } 198 199 class TestClassLoader extends ClassLoader { 200 201 HashMap<String, byte[]> namedBytes = new HashMap<>(); 202 ArrayList<String> findNames = new ArrayList<String>(); 203 204 TestClassLoader() {} 205 TestClassLoader(String name, byte[] classBytes) { 206 addNamedBytes(name, classBytes); 207 } 208 209 void addNamedBytes(String name, byte[] classBytes) { 210 namedBytes.put(name, classBytes); 211 } 212 213 @Override 214 public Class findClass(String name) throws ClassNotFoundException { 215 byte[] classBytes = null; 216 synchronized (findNames) { 217 findNames.add(name); 218 classBytes = namedBytes.get(name); 219 } 220 if (classBytes != null) { 221 return defineClass(name, classBytes, 0, classBytes.length); 222 } 223 throw new ClassNotFoundException(name); 224 } 225 226 public ArrayList<String> getFindNames() { 227 return findNames; 228 } 229 } 230 231 void loadDvtFirst() { 232 try { 233 loadDvtFirstNoVcc(); 234 loadDvtFirstNotVcc(); 235 loadDvtFirstBadVcc(); 236 loadDvtFirstVcc(); 237 } catch (Throwable t) { 238 fail("loadDvtFirst failed", t); 239 } 240 } 241 242 void loadDvtFirstNoVcc() throws Throwable { 243 String vccName = "TestNoVcc"; 244 try { 245 newDvtUserInstance(vccName, null, false); 246 } catch (NoClassDefFoundError ncdfe) {} 247 try { 248 newDvtUserInstance(vccName, null, true); 249 } catch (NoClassDefFoundError ncdfe) {} 250 } 251 252 void loadDvtFirstNotVcc() throws Throwable { 253 String vccName = "TestNotVcc"; 254 byte[] vccBytes = createTestVccClassBytes(vccName, false); 255 try { 256 newDvtUserInstance(vccName, vccBytes, false); 257 } catch (NoClassDefFoundError ncdfe) {} 258 try { 259 newDvtUserInstance(vccName, vccBytes, true); 260 } catch (NoClassDefFoundError ncdfe) {} 261 } 262 263 void loadDvtFirstBadVcc() throws Throwable { 264 String vccName = "TestBadVcc"; 265 byte[] vccBytes = createTestVccClassBytes(vccName, TEST_DEF_CLASS_ACCESS, 266 true, OBJECT_CLASS_DESC, "I", 267 ACC_PUBLIC); 268 try { 269 newDvtUserInstance(vccName, vccBytes, false); 270 } catch (IncompatibleClassChangeError icce) {} 271 try { 272 newDvtUserInstance(vccName, vccBytes, true); 273 } catch (IncompatibleClassChangeError icce) {} 274 } 275 276 void loadDvtFirstVcc() throws Throwable { 277 String vccName = "TestValidVcc"; 278 byte[] vccBytes = createTestVccClassBytes(vccName, TEST_DEF_CLASS_ACCESS, 279 true, OBJECT_CLASS_DESC, "I", 280 TEST_DEF_FIELD_ACCESS); 281 newDvtUserInstance(vccName, vccBytes, false); 282 newDvtUserInstance(vccName, vccBytes, true); 283 } 284 285 void newDvtUserInstance(String vccName, byte[] vccBytes, boolean withField) throws Throwable { 286 TestClassLoader cl = new TestClassLoader(); 287 if (vccBytes != null) { 288 cl.addNamedBytes(vccName, vccBytes); 289 } 290 String dvtUserName = "UseValidDvt"; 291 String dvtName = vccName + DVT_SUFFIX; 292 String dvtFieldDesc = "Q" + dvtName + ";"; 293 String dvtClassDesc = ";" + dvtFieldDesc; 294 byte[] classBytes = createTestDvtUserClassBytes(dvtUserName, dvtClassDesc, (withField) ? dvtFieldDesc : null); 295 cl.addNamedBytes(dvtUserName, classBytes); 296 try { 297 Class.forName(dvtUserName, true, cl).getDeclaredConstructor().newInstance(); 298 } catch (InvocationTargetException ite) { throw ite.getTargetException(); } 299 } 300 301 byte[] createTestDvtUserClassBytes(String className, String dvtDesc, String dvtFieldDesc) { 302 BasicClassBuilder builder = new BasicClassBuilder(className, 53, 1) 303 .withFlags(Flag.ACC_PUBLIC) 304 .withSuperclass("java/lang/Object") 305 .withMethod("<init>", "()V", M -> 306 M.withFlags(Flag.ACC_PUBLIC).withCode(TypedCodeBuilder::new, C -> 307 C 308 .load(0).invokespecial("java/lang/Object", "<init>", "()V", false) 309 .iconst_1().anewarray(dvtDesc).pop() 310 .return_())); 311 if (dvtFieldDesc != null) { 312 builder.withField("dvtField", dvtFieldDesc); 313 } 314 return builder.build(); 315 } 316 }