< prev index next >

hotspot/test/runtime/valhalla/valuetypes/DeriveValueTypeCreation.java

Print this page

        

@@ -20,18 +20,19 @@
  * 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.InvocationTargetException;
 import java.lang.reflect.Method;
 import static java.lang.reflect.Modifier.*;
 import java.net.URL;
-import java.util.Enumeration;
+import java.util.ArrayList;
+import java.util.HashMap;
 
+import jdk.experimental.bytecode.*;
 import jdk.experimental.value.ValueType;
 
 import jdk.internal.org.objectweb.asm.*;
 import static jdk.internal.org.objectweb.asm.Opcodes.*;
 

@@ -39,27 +40,34 @@
 
 /*
  * @test DeriveValueTypeCreation
  * @summary Derive Value Type creation test
  * @library /test/lib
+ * @compile DeriveValueTypeCreation.java
  * @modules java.base/jdk.internal.org.objectweb.asm
  * @build runtime.valhalla.valuetypes.ValueCapableClass
  * @run main/othervm -Xint -XX:+EnableMVT runtime.valhalla.valuetypes.DeriveValueTypeCreation
  * @run main/othervm -Xcomp -XX:+EnableMVT runtime.valhalla.valuetypes.DeriveValueTypeCreation
  */
 public class DeriveValueTypeCreation {
 
     public static final String VCC_CLASSNAME = "runtime.valhalla.valuetypes.ValueCapableClass";
+    public static final String DVT_SUFFIX = "$Value";
+
+    public static final int TEST_DEF_CLASS_ACCESS = ACC_SUPER | ACC_PUBLIC | ACC_FINAL;
+    public static final int TEST_DEF_FIELD_ACCESS = ACC_PUBLIC | ACC_FINAL;
+    public static final String OBJECT_CLASS_DESC  = "java/lang/Object";
 
     public static void main(String[] args) {
         DeriveValueTypeCreation test = new DeriveValueTypeCreation();
         test.run();
     }
 
     public void run() {
         loadAndRunTest();
         notValueCapableClasses();
+        loadDvtFirst();
     }
 
     void loadAndRunTest() {
         Class<?> clazz = null;
         try {

@@ -92,11 +100,11 @@
             fail("ValueType.sourceClass() failed");
         }
 
         // DVT class matches our expectations for the current implementation...
         Class<?> vtClass = vt.valueClass();
-        if (!vtClass.getName().equals(clazz.getName() + "$Value")) {
+        if (!vtClass.getName().equals(clazz.getName() + DVT_SUFFIX)) {
             fail("ValueType.valueClass() failed");
         }
         if (!vtClass.getSuperclass().getName().equals("java.lang.__Value")) {
             fail("ValueType.valueClass() isn't a Value Type class");
         }

@@ -112,37 +120,33 @@
             fail("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
+        // First a control test to check createTestVccClass is working
         try {
-            Class<?> cls = createTestClass("Control_Case_is_a_VCC", vccKlassAccess, vccSuperClass, "I", vccFieldAccess);
+            Class<?> cls = createTestVccClass("Control_Case_is_a_VCC", TEST_DEF_CLASS_ACCESS, OBJECT_CLASS_DESC, "I", TEST_DEF_FIELD_ACCESS);
             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");
+        testFailCase("Not_a_final_class", ACC_SUPER | ACC_PUBLIC, OBJECT_CLASS_DESC, "I", TEST_DEF_FIELD_ACCESS, "not a final class");
+        testFailCase("No_fields", TEST_DEF_CLASS_ACCESS, OBJECT_CLASS_DESC, null, TEST_DEF_FIELD_ACCESS, "has no instance fields");
+        testFailCase("Not_final_field", TEST_DEF_CLASS_ACCESS, OBJECT_CLASS_DESC, "I", ACC_PUBLIC, "contains non-final instance field");
+        testFailCase("Super_not_Object", TEST_DEF_CLASS_ACCESS, "java/lang/Throwable", "I", TEST_DEF_FIELD_ACCESS, "does not derive from Object");
     }
 
     void testFailCase(String clsName,
                       int klassAccess,
                       String superKlass,
                       String fieldType,
                       int fieldAccess,
                       String errMsgRequired) {
         try {
-            createTestClass(clsName, klassAccess, superKlass, fieldType, fieldAccess);
+            createTestVccClass(clsName, klassAccess, superKlass, fieldType, fieldAccess);
             fail(clsName + " : failed to fail with Error");
         }
         catch (ClassNotFoundException cnfe) {
             fail(clsName + " : Unexpected ClassNotFoundException", cnfe);
         }

@@ -151,40 +155,163 @@
                 fail(clsName + " : Not the error we were looking for", err);
             }
         }
     }
 
-    Class<?> createTestClass(String name,
+    byte[] createTestVccClassBytes(String name,
+                                boolean vccAnnotation) {
+        return createTestVccClassBytes(name, TEST_DEF_CLASS_ACCESS, vccAnnotation, OBJECT_CLASS_DESC, "I", TEST_DEF_FIELD_ACCESS);
+    }
+
+    byte[] createTestVccClassBytes(String name,
                              int klassAccess,
                              String superKlass,
                              String fieldType,
-                             int fieldAccess) throws ClassNotFoundException {
+                                int fieldAccess)  {
+        return createTestVccClassBytes(name, klassAccess, true, superKlass, fieldType, fieldAccess);
+    }
+
+    byte[] createTestVccClassBytes(String name,
+                                int klassAccess,
+                                boolean vccAnnotation,
+                                String superKlass,
+                                String fieldType,
+                                int fieldAccess)  {
         ClassWriter cw = new ClassWriter(0);
         cw.visit(52, klassAccess, name, null, superKlass, null);
+        if (vccAnnotation ) {
         cw.visitAnnotation("Ljvm/internal/value/ValueCapableClass;", true);
+        }
         if (fieldType != null) {
             cw.visitField(fieldAccess, "x", fieldType, null, null);
         }
         cw.visitEnd();
-        return new TestClassLoader(name, cw.toByteArray()).loadClass(name);
+        return cw.toByteArray();
+    }
+
+    Class<?> createTestVccClass(String name,
+                             int klassAccess,
+                             String superKlass,
+                             String fieldType,
+                             int fieldAccess) throws ClassNotFoundException {
+        return new TestClassLoader(name,
+                                   createTestVccClassBytes(name, klassAccess, superKlass, fieldType, fieldAccess)).loadClass(name);
     }
 
     class TestClassLoader extends ClassLoader {
 
-        String name;
-        byte[] classBytes;
+        HashMap<String, byte[]> namedBytes = new HashMap<>();
+        ArrayList<String> findNames = new ArrayList<String>();
 
+        TestClassLoader() {}
         TestClassLoader(String name, byte[] classBytes) {
-            this.name = name;
-            this.classBytes = classBytes;
+            addNamedBytes(name, classBytes);
+        }
+
+        void addNamedBytes(String name, byte[] classBytes) {
+            namedBytes.put(name, classBytes);
         }
 
         @Override
         public Class findClass(String name) throws ClassNotFoundException {
-            if (this.name.equals(name)) {
+            byte[] classBytes = null;
+            synchronized (findNames) {
+                findNames.add(name);
+                classBytes = namedBytes.get(name);
+            }
+            if (classBytes != null) {
                 return defineClass(name, classBytes, 0, classBytes.length);
             }
-            throw new ClassNotFoundException();
+            throw new ClassNotFoundException(name);
+        }
+
+        public ArrayList<String> getFindNames() {
+            return findNames;
         }
     }
 
+    void loadDvtFirst() {
+        try {
+            loadDvtFirstNoVcc();
+            loadDvtFirstNotVcc();
+            loadDvtFirstBadVcc();
+            loadDvtFirstVcc();
+        } catch (Throwable t) {
+            fail("loadDvtFirst failed", t);
+        }
+    }
+
+    void loadDvtFirstNoVcc() throws Throwable {
+        String vccName = "TestNoVcc";
+        try {
+            newDvtUserInstance(vccName, null, false);
+        } catch (NoClassDefFoundError ncdfe) {}
+        try {
+            newDvtUserInstance(vccName, null, true);
+        } catch (NoClassDefFoundError ncdfe) {}
+    }
+
+    void loadDvtFirstNotVcc() throws Throwable {
+        String vccName = "TestNotVcc";
+        byte[] vccBytes = createTestVccClassBytes(vccName, false);
+        try {
+            newDvtUserInstance(vccName, vccBytes, false);
+        } catch (NoClassDefFoundError ncdfe) {}
+        try {
+            newDvtUserInstance(vccName, vccBytes, true);
+        } catch (NoClassDefFoundError ncdfe) {}
+    }
+
+    void loadDvtFirstBadVcc() throws Throwable {
+        String vccName = "TestBadVcc";
+        byte[] vccBytes = createTestVccClassBytes(vccName, TEST_DEF_CLASS_ACCESS,
+                                                  true, OBJECT_CLASS_DESC, "I",
+                                                  ACC_PUBLIC);
+        try {
+            newDvtUserInstance(vccName, vccBytes, false);
+        } catch (IncompatibleClassChangeError icce) {}
+        try {
+            newDvtUserInstance(vccName, vccBytes, true);
+        } catch (IncompatibleClassChangeError icce) {}
+    }
+
+    void loadDvtFirstVcc() throws Throwable {
+        String vccName = "TestValidVcc";
+        byte[] vccBytes = createTestVccClassBytes(vccName, TEST_DEF_CLASS_ACCESS,
+                                                  true, OBJECT_CLASS_DESC, "I",
+                                                  TEST_DEF_FIELD_ACCESS);
+        newDvtUserInstance(vccName, vccBytes, false);
+        newDvtUserInstance(vccName, vccBytes, true);
+    }
+
+    void newDvtUserInstance(String vccName, byte[] vccBytes, boolean withField) throws Throwable {
+        TestClassLoader cl = new TestClassLoader();
+        if (vccBytes != null) {
+            cl.addNamedBytes(vccName, vccBytes);
+        }
+        String dvtUserName = "UseValidDvt";
+        String dvtName = vccName + DVT_SUFFIX;
+        String dvtFieldDesc = "Q" + dvtName + ";";
+        String dvtClassDesc = ";" + dvtFieldDesc;
+        byte[] classBytes = createTestDvtUserClassBytes(dvtUserName, dvtClassDesc, (withField) ? dvtFieldDesc : null);
+        cl.addNamedBytes(dvtUserName, classBytes);
+        try {
+            Class.forName(dvtUserName, true, cl).getDeclaredConstructor().newInstance();
+        } catch (InvocationTargetException ite) { throw ite.getTargetException(); }
+    }
+
+    byte[] createTestDvtUserClassBytes(String className, String dvtDesc, String dvtFieldDesc) {
+        BasicClassBuilder builder = new BasicClassBuilder(className, 53, 1)
+            .withFlags(Flag.ACC_PUBLIC)
+            .withSuperclass("java/lang/Object")
+            .withMethod("<init>", "()V", M ->
+                M.withFlags(Flag.ACC_PUBLIC).withCode(TypedCodeBuilder::new, C ->
+                    C
+                    .load(0).invokespecial("java/lang/Object", "<init>", "()V", false)
+                    .iconst_1().anewarray(dvtDesc).pop()
+                    .return_()));
+        if (dvtFieldDesc != null) {
+            builder.withField("dvtField", dvtFieldDesc);
+        }
+        return builder.build();
+    }
 }
< prev index next >