/* * 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 runtime.valhalla.valuetypes; import java.io.IOException; import java.io.RandomAccessFile; import java.lang.reflect.Field; import java.lang.reflect.Method; import static java.lang.reflect.Modifier.*; import java.net.URL; import java.util.Enumeration; import jdk.experimental.value.ValueType; import jdk.internal.org.objectweb.asm.*; import static jdk.internal.org.objectweb.asm.Opcodes.*; import static jdk.test.lib.Asserts.*; /* * @test DeriveValueTypeCreation * @summary Derive Value Type creation test * @library /testlibrary / * @build runtime.valhalla.valuetypes.ValueCapableClass * @run main/othervm -Xint -noverify runtime.valhalla.valuetypes.DeriveValueTypeCreation * @run main/othervm -Xcomp -noverify runtime.valhalla.valuetypes.DeriveValueTypeCreation */ public class DeriveValueTypeCreation { public static final String VCC_CLASSNAME = "runtime.valhalla.valuetypes.ValueCapableClass"; static final boolean MVT_1_0 = false; // "Some restrictions apply" static final boolean MVT_1_1 = true; // "References support added" public static void main(String[] args) { DeriveValueTypeCreation test = new DeriveValueTypeCreation(); test.run(); } public void run() { loadAndRunTest(); notValueCapableClasses(); } void loadAndRunTest() { Class clazz = null; try { clazz = Class.forName(VCC_CLASSNAME, true, getClass().getClassLoader()); clazz.getDeclaredMethod("test").invoke(null); } catch (ClassNotFoundException cnfe) { fail("VCC class missing", cnfe); } catch (NoSuchMethodException nsme) { fail("VCC test method missing", nsme); } catch (Throwable t) { fail("Failed to invoke VCC.test()", t); } checkValueCapableClass(clazz); } void checkValueCapableClass(Class clazz) { if (!ValueType.classHasValueType(clazz)) { error("!classHasValueType: " + clazz); } ValueType vt = ValueType.forClass(clazz); if (vt == null) { error("ValueType.forClass failed"); } System.out.println("ValueType: " + vt); if (vt.boxClass() != clazz) { error("ValueType.boxClass() failed"); } if (vt.sourceClass() != clazz) { error("ValueType.sourceClass() failed"); } // DVT class matches our expectations for the current implementation... Class vtClass = vt.valueClass(); if (!vtClass.getName().equals(clazz.getName() + "$Value")) { error("ValueType.valueClass() failed"); } if (!vtClass.getSuperclass().getName().equals("java.lang.__Value")) { error("ValueType.valueClass() isn't a Value Type class"); } if (MVT_1_0) { if (!valhalla.shady.MinimalValueTypes_1_0.isValueType(vtClass)) { error("ValueType.valueClass() isn't a Value Type class according to MVT1.0"); } } // Exercise "Class.getSimpleName()", we've cause problems with it before String sn = vtClass.getSimpleName(); System.out.println("SimpleName: " + sn); if (clazz.getClassLoader() != vtClass.getClassLoader()) { error("ClassLoader mismatch"); } if (clazz.getProtectionDomain() != vtClass.getProtectionDomain()) { error("ProtectionDomain mismatch"); } } void notValueCapableClasses() { int vccKlassAccess = ACC_SUPER | ACC_PUBLIC | ACC_FINAL; int vccFieldAccess = ACC_PUBLIC | ACC_FINAL; String vccSuperClass = "java/lang/Object"; // First a control test to check createTestClass is working try { Class cls = createTestClass("Control_Case_is_a_VCC", vccKlassAccess, vccSuperClass, "I", vccFieldAccess); checkValueCapableClass(cls); } catch (Exception e) { fail("Control test failed", e); } testFailCase("Not_a_final_class", ACC_SUPER | ACC_PUBLIC, vccSuperClass, "I", vccFieldAccess, "not a final class"); testFailCase("No_fields", vccKlassAccess, vccSuperClass, null, vccFieldAccess, "has no instance fields"); testFailCase("Not_final_field", vccKlassAccess, vccSuperClass, "I", ACC_PUBLIC, "contains non-final instance field"); testFailCase("Super_not_Object", vccKlassAccess, "java/lang/Throwable", "I", vccFieldAccess, "does not derive from Object"); if (MVT_1_0) { String notSupported = "do not support"; testFailCase("Only_Primitve_Fields_String", vccKlassAccess, vccSuperClass, "Ljava/lang/String;", vccFieldAccess, notSupported); testFailCase("Only_Primitve_Fields_Array", vccKlassAccess, vccSuperClass, "[I", vccFieldAccess, notSupported); } } void testFailCase(String clsName, int klassAccess, String superKlass, String fieldType, int fieldAccess, String errMsgRequired) { try { createTestClass(clsName, klassAccess, superKlass, fieldType, fieldAccess); error(clsName + " : failed to fail with Error"); } catch (ClassNotFoundException cnfe) { fail(clsName + " : Unexpected ClassNotFoundException", cnfe); } catch (Error err) { if (!err.getMessage().contains(errMsgRequired)) { fail(clsName + " : Not the error we were looking for", err); } } } Class createTestClass(String name, int klassAccess, String superKlass, String fieldType, int fieldAccess) throws ClassNotFoundException { ClassWriter cw = new ClassWriter(0); cw.visit(52, klassAccess, name, null, superKlass, null); cw.visitAnnotation("Ljvm/internal/value/DeriveValueType;", true); if (fieldType != null) { cw.visitField(fieldAccess, "x", fieldType, null, null); } cw.visitEnd(); return new TestClassLoader(name, cw.toByteArray()).loadClass(name); } class TestClassLoader extends ClassLoader { String name; byte[] classBytes; TestClassLoader(String name, byte[] classBytes) { this.name = name; this.classBytes = classBytes; } @Override public Class findClass(String name) throws ClassNotFoundException { if (this.name.equals(name)) { return defineClass(name, classBytes, 0, classBytes.length); } throw new ClassNotFoundException(); } } /* TODO: Current repo state doesn't pick up the common test/lib Asserts remove this implementation when fixed */ public static void fail(String msg, Throwable thr) { // Missing Asserts.fail(String, Throwable) throw new RuntimeException(msg, thr); } public static void error(String msg) { // Missing Asserts.error(String) throw new RuntimeException(msg); } }