changeset 58164:3ff43480c2a2 nestmates

8230928: [TESTBUG] Add hotspot tests for hidden classes and weak classes Summary: Add new tests adapted from unsafe anonymous class tests Reviewed-by: fparain, mchung
author hseigel
date Tue, 07 Jan 2020 13:49:31 +0000
parents 5badb551e411
children b2325720e6e2
files test/hotspot/jtreg/runtime/HiddenClasses/CastToParentTest.java test/hotspot/jtreg/runtime/HiddenClasses/GCHiddenClass.java test/hotspot/jtreg/runtime/HiddenClasses/HiddenClassStack.java test/hotspot/jtreg/runtime/HiddenClasses/HiddenDefMeths.java test/hotspot/jtreg/runtime/HiddenClasses/HiddenGetModule.java test/hotspot/jtreg/runtime/HiddenClasses/InstantiateHiddenClass.java test/hotspot/jtreg/runtime/HiddenClasses/NestedHidden.java test/hotspot/jtreg/runtime/HiddenClasses/StressHiddenClasses.java test/hotspot/jtreg/runtime/HiddenClasses/TestHiddenClassUnloading.java test/hotspot/jtreg/runtime/HiddenClasses/pkg/HasNamedModule.java
diffstat 10 files changed, 1005 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/HiddenClasses/CastToParentTest.java	Tue Jan 07 13:49:31 2020 +0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2020, 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 that a hidden class can be cast to its parent.
+ * @library /test/lib
+ * @modules java.compiler
+ *          java.management
+ * @run main CastToParentTest
+ */
+
+import java.lang.invoke.MethodType;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*;
+import jdk.test.lib.compiler.InMemoryJavaCompiler;
+
+// This test is based on vmTestbase/vm/mlvm/anonloader/func/castToGrandparent/Test.java
+public class CastToParentTest {
+
+    static byte klassbuf[] = InMemoryJavaCompiler.compile("TestClass",
+        "public class TestClass extends CastToParentTest { " +
+        "    public static void concat(String one, String two) throws Throwable { " +
+        "        System.out.println(one + two);" +
+        " } } ");
+
+    public static void main(String[] args) throws Throwable {
+        Lookup lookup = MethodHandles.lookup();
+        Class<?> c = lookup.defineHiddenClass(klassbuf, false, NESTMATE).lookupClass();
+        Object hiddenClassObj = c.newInstance();
+
+        // Cast hidden class to its parent.
+        CastToParentTest parentObj = (CastToParentTest)hiddenClassObj;
+
+        if (!parentObj.equals(hiddenClassObj)) {
+            throw new RuntimeException("Hidden class object cannot be cast to parent");
+        }
+
+        // Try to cast using a different mechanism.
+        new CastToParentTest().getClass().cast(hiddenClassObj);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/HiddenClasses/GCHiddenClass.java	Tue Jan 07 13:49:31 2020 +0000
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2020, 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 that hidden classes get garbage collected.
+ * @library /test/lib
+ * @modules java.compiler
+ *          java.management
+ * @run main GCHiddenClass
+ */
+
+
+import java.lang.invoke.MethodType;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.ref.PhantomReference;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+
+import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*;
+import jdk.test.lib.compiler.InMemoryJavaCompiler;
+
+// This test is based on test vmTestbase/vm/mlvm/anonloader/func/isGarbageCollected/Test.java
+public class GCHiddenClass {
+
+    static byte klassbuf[] = InMemoryJavaCompiler.compile("TestClass",
+        "public class TestClass { " +
+        "    public TestClass() { " +
+        "        System.out.println(\"Hello\"); " +
+        " } } ");
+
+    // A private method is great to keep hidden Class reference local to make it
+    // GCed on the next cycle
+    private PhantomReference<Class<?>> createClass(ReferenceQueue<Class<?>> refQueue) throws Exception {
+        Lookup lookup = MethodHandles.lookup();
+        Class<?> cl = lookup.defineHiddenClass(klassbuf, false, NESTMATE, WEAK).lookupClass();
+        return new PhantomReference<Class<?>>(cl, refQueue);
+    }
+
+    public boolean run() throws Exception {
+        ReferenceQueue<Class<?>> refQueue = new ReferenceQueue<Class<?>>();
+        PhantomReference<Class<?>> hiddenClassRef = createClass(refQueue);
+        System.gc();
+        Reference<? extends Class<?>> deletedObject = refQueue.remove();
+        return hiddenClassRef.equals(deletedObject);
+    }
+
+    public static void main(String[] args) throws Throwable {
+        GCHiddenClass gcHC = new GCHiddenClass();
+        if (!gcHC.run()) {
+            throw new RuntimeException("Test failed");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/HiddenClasses/HiddenClassStack.java	Tue Jan 07 13:49:31 2020 +0000
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020, 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 that stack tracing isn't broken if an exception is thrown
+ *          in a hidden class.
+ * @library /test/lib
+ * @modules java.compiler
+ *          java.management
+ * @run main HiddenClassStack
+ */
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.lang.invoke.MethodType;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*;
+import jdk.test.lib.compiler.InMemoryJavaCompiler;
+
+// This test is based on vmTestbase/vm/mlvm/anonloader/func/classNameInStackTrace/Test.java
+public class HiddenClassStack {
+
+    static byte klassbuf[] = InMemoryJavaCompiler.compile("TestClass",
+        "public class TestClass { " +
+        "    public TestClass() { " +
+        "        throw new RuntimeException(\"boom\"); " +
+        " } } ");
+
+    public static void main(String[] args) throws Throwable {
+
+        // An exception is thrown by class loaded by lookup.defineHiddenClass().
+        // Verify that the exception's stack trace contains name of the current
+        // test class.
+        try {
+            Lookup lookup = MethodHandles.lookup();
+            Class<?> cl = lookup.defineHiddenClass(klassbuf, false, NESTMATE).lookupClass();
+            Object obj = cl.newInstance();
+            throw new Exception("Expected RuntimeException not thrown");
+        } catch (RuntimeException e) {
+            if (!e.getMessage().contains("boom")) {
+                throw new RuntimeException("Wrong RuntimeException, e: " + e.toString());
+            }
+            ByteArrayOutputStream byteOS = new ByteArrayOutputStream();
+            PrintStream printStream = new PrintStream(byteOS);
+            e.printStackTrace(printStream);
+            printStream.close();
+            String stackTrace = byteOS.toString("ASCII");
+            if (!stackTrace.contains(HiddenClassStack.class.getName())) {
+                throw new RuntimeException("HiddenClassStack missing from stacktrace: " +
+                                           stackTrace);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/HiddenClasses/HiddenDefMeths.java	Tue Jan 07 13:49:31 2020 +0000
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2020, 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 Tests a hidden class that implements interfaces with default methods.
+ * @library /testlibrary
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ *          java.management
+ * @run main HiddenDefMeths
+ */
+
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Type;
+
+import java.lang.invoke.MethodType;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PRIVATE;
+import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
+import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER;
+import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD;
+import static jdk.internal.org.objectweb.asm.Opcodes.ARETURN;
+import static jdk.internal.org.objectweb.asm.Opcodes.DUP;
+import static jdk.internal.org.objectweb.asm.Opcodes.GETFIELD;
+import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL;
+import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD;
+import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
+import static jdk.internal.org.objectweb.asm.Opcodes.V1_8;
+
+public class HiddenDefMeths {
+
+    interface Resource {
+        Pointer ptr();
+    }
+
+    interface Struct extends Resource {
+       StructPointer ptr();
+    }
+
+    interface Pointer { }
+
+    interface StructPointer extends Pointer { }
+
+    interface I extends Struct {
+        void m();
+    }
+
+    static String IMPL_PREFIX = "$$impl";
+    static String PTR_FIELD_NAME = "ptr";
+
+    // Generate a class similar to:
+    //
+    // public class HiddenDefMeths$I$$impl implements HiddenDefMeths$I, HiddenDefMeths$Struct {
+    //
+    //     public HiddenDefMeths$StructPointer ptr;
+    //
+    //     public HiddenDefMeths$I$$impl(HiddenDefMeths$StructPointer p) {
+    //         ptr = p;
+    //     }
+    //
+    //     public HiddenDefMeths$StructPointer ptr() {
+    //         return ptr;
+    //     }
+    // }
+    //
+    byte[] generate(Class<?> iface) {
+        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+
+        String ifaceTypeName = Type.getInternalName(iface);
+        String proxyClassName = ifaceTypeName + IMPL_PREFIX;
+        // class definition
+        cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, proxyClassName,
+                desc(Object.class) + desc(ifaceTypeName) + desc(Struct.class),
+                name(Object.class),
+                new String[] { ifaceTypeName, name(Struct.class) });
+
+        cw.visitField(ACC_PUBLIC, PTR_FIELD_NAME, desc(StructPointer.class), desc(StructPointer.class), null);
+        cw.visitEnd();
+
+        // constructor
+        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>",
+                meth(desc(void.class), desc(StructPointer.class)),
+                meth(desc(void.class), desc(StructPointer.class)), null);
+        mv.visitCode();
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitInsn(DUP);
+        mv.visitMethodInsn(INVOKESPECIAL, name(Object.class), "<init>", meth(desc(void.class)), false);
+        mv.visitVarInsn(ALOAD, 1);
+        // Execution of this PUTFIELD instruction causes the bug's ClassNotFoundException.
+        mv.visitFieldInsn(PUTFIELD, proxyClassName, PTR_FIELD_NAME, desc(StructPointer.class));
+        mv.visitInsn(RETURN);
+        mv.visitMaxs(0, 0);
+        mv.visitEnd();
+
+        // ptr() impl
+        mv = cw.visitMethod(ACC_PUBLIC, PTR_FIELD_NAME, meth(desc(StructPointer.class)),
+                meth(desc(StructPointer.class)), null);
+        mv.visitCode();
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitFieldInsn(GETFIELD, proxyClassName, PTR_FIELD_NAME, desc(StructPointer.class));
+        mv.visitInsn(ARETURN);
+        mv.visitMaxs(0, 0);
+        mv.visitEnd();
+
+        return cw.toByteArray();
+    }
+
+    String name(Class<?> clazz) {
+        if (clazz.isPrimitive()) {
+            throw new IllegalStateException();
+        } else if (clazz.isArray()) {
+            return desc(clazz);
+        } else {
+            return clazz.getName().replaceAll("\\.", "/");
+        }
+    }
+
+    String desc(Class<?> clazz) {
+        String mdesc = MethodType.methodType(clazz).toMethodDescriptorString();
+        return mdesc.substring(mdesc.indexOf(')') + 1);
+    }
+
+    String desc(String clazzName) {
+        return "L" + clazzName + ";";
+    }
+
+    String gen(String clazz, String... typeargs) {
+        return clazz.substring(0, clazz.length() - 1) + Stream.of(typeargs).collect(Collectors.joining("", "<", ">")) + ";";
+    }
+
+    String meth(String restype, String... argtypes) {
+        return Stream.of(argtypes).collect(Collectors.joining("", "(", ")")) + restype;
+    }
+
+    String meth(Method m) {
+        return MethodType.methodType(m.getReturnType(), m.getParameterTypes()).toMethodDescriptorString();
+    }
+
+    public static void main(String[] args) throws Throwable {
+        byte[] bytes = new HiddenDefMeths().generate(I.class);
+        Lookup lookup = MethodHandles.lookup();
+        Class<?> cl = lookup.defineHiddenClass(bytes, false, NESTMATE).lookupClass();
+        I i = (I)cl.getConstructors()[0].newInstance(new Object[] { null });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/HiddenClasses/HiddenGetModule.java	Tue Jan 07 13:49:31 2020 +0000
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2020, 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 that a hidden class has the same module as its lookup class.
+ * @library /test/lib
+ * @modules java.compiler
+ *          java.management
+ * @compile pkg/HasNamedModule.java
+ * @run main/othervm HiddenGetModule
+ */
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.lang.invoke.MethodType;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*;
+import java.io.IOException;
+import java.lang.ModuleLayer;
+import java.lang.module.Configuration;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReader;
+import java.lang.module.ModuleReference;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+
+import jdk.test.lib.compiler.InMemoryJavaCompiler;
+
+public class HiddenGetModule {
+
+   static byte unnamedKlassbuf[] = InMemoryJavaCompiler.compile("TestClass",
+       "public class TestClass { " +
+       "    public static void concat(String one, String two) throws Throwable { " +
+       "        System.out.println(one + two);" +
+       " } } ");
+
+    public static ModuleFinder finderOf(ModuleDescriptor... descriptors) {
+
+        // Create a ModuleReference for each module
+        Map<String, ModuleReference> namesToReference = new HashMap<>();
+
+        for (ModuleDescriptor descriptor : descriptors) {
+            String name = descriptor.name();
+
+            URI uri = URI.create("module:/" + name);
+
+            ModuleReference mref = new ModuleReference(descriptor, uri) {
+                @Override
+                public ModuleReader open() {
+                    throw new UnsupportedOperationException();
+                }
+            };
+
+            namesToReference.put(name, mref);
+        }
+
+        return new ModuleFinder() {
+            @Override
+            public Optional<ModuleReference> find(String name) {
+                Objects.requireNonNull(name);
+                return Optional.ofNullable(namesToReference.get(name));
+            }
+            @Override
+            public Set<ModuleReference> findAll() {
+                return new HashSet<>(namesToReference.values());
+            }
+        };
+    }
+
+    public static void main(String[] args) throws Throwable {
+
+        // Test unnamed module.
+        Lookup lookup = MethodHandles.lookup();
+        Class<?> cl = lookup.defineHiddenClass(unnamedKlassbuf, false, NESTMATE).lookupClass();
+        if (cl.getModule() != HiddenGetModule.class.getModule()) {
+            throw new RuntimeException("hidden class and lookup class have different unnamed modules");
+        }
+
+        // Test named module.
+        MyClassLoader myClassLoader = new MyClassLoader();
+
+        // Define a module named HiddenModule containing package pkg.
+        ModuleDescriptor descriptor = ModuleDescriptor.newModule("HiddenModule")
+                .requires("java.base")
+                .exports("pkg")
+                .build();
+
+        // Set up a ModuleFinder containing the module for this layer.
+        ModuleFinder finder = finderOf(descriptor);
+
+        // Resolves "HiddenModule"
+        Configuration cf = ModuleLayer.boot()
+                .configuration()
+                .resolve(finder, ModuleFinder.of(), Set.of("HiddenModule"));
+
+        // map module to class loader
+        Map<String, ClassLoader> map = new HashMap<>();
+        map.put("HiddenModule", myClassLoader);
+
+        // Create layer that contains HiddenModule
+        ModuleLayer layer = ModuleLayer.boot().defineModules(cf, map::get);
+
+        byte klassbuf[] = InMemoryJavaCompiler.compile("pkg.TestClass",
+            "package pkg; " +
+            "public class TestClass { " +
+            "    public static void concat(String one, String two) throws Throwable { " +
+            "        System.out.println(one + two);" +
+            " } } ");
+
+        // Load the class and call the method that defines a hidden class and compares modules.
+        Class<?>c = Class.forName("pkg.HasNamedModule", true, myClassLoader);
+        if (c.getClassLoader() != myClassLoader) {
+            throw new RuntimeException("pkg.HasNamedModule defined by wrong classloader: " + c.getClassLoader());
+        }
+        Method m = c.getDeclaredMethod("compareModules", byte[].class);
+        m.invoke(null, klassbuf);
+    }
+
+
+    public static class MyClassLoader extends ClassLoader {
+
+        public static final String CLASS_NAME = "HasNamedModule";
+
+        static ByteBuffer readClassFile(String name) {
+            File f = new File(System.getProperty("test.classes", "."), name);
+            try (FileInputStream fin = new FileInputStream(f);
+                 FileChannel fc = fin.getChannel()) {
+                return fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
+            } catch (IOException e) {
+                throw new RuntimeException("Can't open file: " + name + ", " + e.toString());
+            }
+        }
+
+        protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+            Class<?> c;
+            if (!name.contains(CLASS_NAME)) {
+                c = super.loadClass(name, resolve);
+            } else {
+                // should not delegate to the system class loader
+                c = findClass(name);
+                if (resolve) {
+                    resolveClass(c);
+                }
+            }
+            return c;
+        }
+
+        protected Class<?> findClass(String name) throws ClassNotFoundException {
+            if (!name.contains(CLASS_NAME)) {
+                throw new ClassNotFoundException("Unexpected class: " + name);
+            }
+            return defineClass(name, readClassFile(name.replace(".", File.separator) + ".class"), null);
+        }
+    } /* MyClassLoader */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/HiddenClasses/InstantiateHiddenClass.java	Tue Jan 07 13:49:31 2020 +0000
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2020, 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 issues with instantiating hidden classes.
+ * @library /test/lib
+ * @modules java.compiler
+ *          java.management
+ * @run main InstantiateHiddenClass
+ */
+
+import java.lang.invoke.MethodType;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*;
+import jdk.test.lib.compiler.InMemoryJavaCompiler;
+
+public class InstantiateHiddenClass {
+
+    static byte klassbuf[] = InMemoryJavaCompiler.compile("TestClass",
+        "public class TestClass { " +
+        "    public static void concat(String one, String two) throws Throwable { " +
+        "        System.out.println(one + two);" +
+        " } } ");
+
+    public static void main(String[] args) throws Throwable {
+
+        // Test that a hidden class cannot be found through its name.
+        try {
+            Lookup lookup = MethodHandles.lookup();
+            Class<?> cl = lookup.defineHiddenClass(klassbuf, false, NESTMATE).lookupClass();
+            Class.forName(cl.getName()).newInstance();
+            throw new RuntimeException("Expected ClassNotFoundException not thrown");
+        } catch (ClassNotFoundException e ) {
+            // Test passed
+        }
+
+
+        // Create two hidden classes and instantiate an object from each of them.
+        // Verify that the references to these objects are different and references
+        // to their classes are not equal either.
+        Lookup lookup = MethodHandles.lookup();
+        Class<?> c1 = lookup.defineHiddenClass(klassbuf, false, NESTMATE).lookupClass();
+        Class<?> c2 = lookup.defineHiddenClass(klassbuf, false, NESTMATE).lookupClass();
+        Object o1 = c1.newInstance();
+        Object o2 = c2.newInstance();
+        if (o1 == o2) {
+            throw new RuntimeException("Objects should not be equal");
+        }
+        if (o1.getClass() == o2.getClass()) {
+            throw new RuntimeException("Classes should not be equal");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/HiddenClasses/NestedHidden.java	Tue Jan 07 13:49:31 2020 +0000
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2020, 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 Creates a hidden class inside of a hidden class.
+ * @library /test/lib
+ * @modules java.compiler
+ *          java.management
+ * @run main p.NestedHidden
+ */
+
+package p;
+
+import java.lang.*;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*;
+import jdk.test.lib.compiler.InMemoryJavaCompiler;
+
+
+// Test that a hidden class can define its own hidden class by calling
+// lookup.defineHiddenClass().
+public class NestedHidden {
+    static byte klassbuf[] = InMemoryJavaCompiler.compile("p.TestClass",
+        "package p; " +
+        "public class TestClass { " +
+        "    public static void concat(String one, String two) throws Throwable { " +
+        "        System.out.println(one + two);" +
+        " } } ");
+
+    public static void main(String args[]) throws Exception {
+        // The hidden class calls lookup.defineHiddenClass(), creating a nested hidden class.
+        byte klassbuf2[] = InMemoryJavaCompiler.compile("p.TestClass2",
+            "package p; " +
+            "import java.lang.invoke.MethodHandles; " +
+            "import java.lang.invoke.MethodHandles.Lookup; " +
+            "import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*; " +
+            "public class TestClass2 { " +
+            "    public static void doit() throws Throwable { " +
+            "        Lookup lookup = MethodHandles.lookup(); " +
+            "        Class<?> klass2 = lookup.defineHiddenClass(p.NestedHidden.klassbuf, true, NESTMATE).lookupClass(); " +
+            "        Class[] dArgs = new Class[2]; " +
+            "        dArgs[0] = String.class; " +
+            "        dArgs[1] = String.class; " +
+            "        try { " +
+            "            klass2.getMethod(\"concat\", dArgs).invoke(null, \"CC\", \"DD\"); " +
+            "        } catch (Throwable ex) { " +
+            "            throw new RuntimeException(\"Exception: \" + ex.toString()); " +
+            "        } " +
+            "} } ");
+
+        Lookup lookup = MethodHandles.lookup();
+        Class<?> klass2 = lookup.defineHiddenClass(klassbuf2, true, NESTMATE).lookupClass();
+        klass2.getMethod("doit").invoke(null);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/HiddenClasses/StressHiddenClasses.java	Tue Jan 07 13:49:31 2020 +0000
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2020, 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 Stress defining hidden classes.
+ * @library /test/lib
+ * @modules java.compiler
+ *          java.management
+ * @run main/othervm StressHiddenClasses
+ */
+
+import java.lang.invoke.MethodType;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*;
+import jdk.test.lib.compiler.InMemoryJavaCompiler;
+
+// This test is based on vmTestbase/vm/mlvm/anonloader/share/StressClassLoadingTest.java
+public class StressHiddenClasses {
+
+    private static final int PARSE_TIMEOUT = 0;
+    private static final int ITERATIONS = 40000;
+
+    static byte klassbuf[] = InMemoryJavaCompiler.compile("TestClass",
+        "public class TestClass { " +
+        "    public static void concat(String one, String two) throws Throwable { " +
+        "        System.out.println(one + two);" +
+        " } } ");
+
+
+    public void run() throws Exception {
+        for (int x = 0; x < ITERATIONS; x++) {
+            Thread parserThread  = new Thread() {
+                public void run() {
+                    try {
+                        Lookup lookup = MethodHandles.lookup();
+                        Class<?> c = lookup.defineHiddenClass(klassbuf, true, NESTMATE, WEAK).lookupClass();
+                    } catch (Throwable e) {
+                        throw new RuntimeException("Unexpected exception: " + e.toString());
+                    }
+                }
+            };
+
+            parserThread.start();
+            parserThread.join(PARSE_TIMEOUT);
+
+            if (parserThread.isAlive()) {
+                System.out.println("parser thread may be hung!");
+                StackTraceElement[] stack = parserThread.getStackTrace();
+                System.out.println("parser thread stack len: " + stack.length);
+                System.out.println(parserThread + " stack trace:");
+                for (int i = 0; i < stack.length; ++i) {
+                    System.out.println(parserThread + "\tat " + stack[i]);
+                }
+
+                parserThread.join(); // Wait until either thread finishes or test times out.
+            }
+        }
+    }
+
+
+    public static void main(String[] args) throws Throwable {
+        StressHiddenClasses shc = new StressHiddenClasses();
+        shc.run();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/HiddenClasses/TestHiddenClassUnloading.java	Tue Jan 07 13:49:31 2020 +0000
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2020, 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 unloading of hidden classes.
+ * @library /test/lib /
+ * @build sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox
+ *                              sun.hotspot.WhiteBox$WhiteBoxPermission
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *      -XX:-BackgroundCompilation
+ *      compiler.classUnloading.hiddenClass.TestHiddenClassUnloading
+ */
+
+package compiler.classUnloading.hiddenClass;
+
+import sun.hotspot.WhiteBox;
+
+import java.io.IOException;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLConnection;
+import compiler.whitebox.CompilerWhiteBoxTest;
+
+// This is based on test compiler/classUnloading/anonymousClass/TestAnonymousClassUnloading.java
+public class TestHiddenClassUnloading {
+    private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
+
+    /**
+     * We override hashCode here to be able to access this implementation
+     * via an Object reference (we cannot cast to TestHiddenClassUnloading).
+     */
+    @Override
+    public int hashCode() {
+        return 42;
+    }
+
+    /**
+     * Does some work by using the hiddenClass.
+     * @param hiddenClass Class performing some work (will be unloaded)
+     */
+    static private void doWork(Class<?> hiddenClass) throws InstantiationException, IllegalAccessException {
+        // Create a new instance
+        Object anon = hiddenClass.newInstance();
+        // We would like to call a method of hiddenClass here but we cannot cast because the class
+        // was loaded by a different class loader. One solution would be to use reflection but since
+        // we want C2 to implement the call as an IC we call Object::hashCode() here which actually
+        // calls hiddenClass::hashCode(). C2 will then implement this call as an IC.
+        if (anon.hashCode() != 42) {
+            new RuntimeException("Work not done");
+        }
+    }
+
+    /**
+     * Makes sure that method is compiled by forcing compilation if not yet compiled.
+     * @param m Method to be checked
+     */
+    static private void makeSureIsCompiled(Method m) {
+        // Make sure background compilation is disabled
+        if (WHITE_BOX.getBooleanVMFlag("BackgroundCompilation")) {
+            throw new RuntimeException("Background compilation enabled");
+        }
+
+        // Check if already compiled
+        if (!WHITE_BOX.isMethodCompiled(m)) {
+            // If not, try to compile it with C2
+            if(!WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION)) {
+                // C2 compiler not available, try to compile with C1
+                WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE);
+            }
+            // Because background compilation is disabled, method should now be compiled
+            if(!WHITE_BOX.isMethodCompiled(m)) {
+                throw new RuntimeException(m + " not compiled");
+            }
+        }
+    }
+
+    /**
+     * This test creates stale Klass* metadata referenced by a compiled IC.
+     *
+     * The following steps are performed:
+     * (1) A hidden version of TestHiddenClassUnloading is loaded by a custom class loader
+     * (2) The method doWork that calls a method of the hidden class is compiled. The call
+     *     is implemented as an IC referencing Klass* metadata of the hidden class.
+     * (3) Unloading of the hidden class is enforced. The IC now references dead metadata.
+     */
+    static public void main(String[] args) throws Exception {
+        // (1) Load a hidden version of this class using method lookup.defineHiddenClass().
+        String rn = TestHiddenClassUnloading.class.getSimpleName() + ".class";
+        URL classUrl = TestHiddenClassUnloading.class.getResource(rn);
+        URLConnection connection = classUrl.openConnection();
+
+        int length = connection.getContentLength();
+        byte[] classBytes = connection.getInputStream().readAllBytes();
+        if (length != -1 && classBytes.length != length) {
+            throw new IOException("Expected:" + length + ", actual: " + classBytes.length);
+        }
+
+        Lookup lookup = MethodHandles.lookup();
+        Class<?> hiddenClass = lookup.defineHiddenClass(classBytes, true, NESTMATE, WEAK).lookupClass();
+
+        // (2) Make sure all paths of doWork are profiled and compiled
+        for (int i = 0; i < 100000; ++i) {
+            doWork(hiddenClass);
+        }
+
+        // Make sure doWork is compiled now
+        Method doWork = TestHiddenClassUnloading.class.getDeclaredMethod("doWork", Class.class);
+        makeSureIsCompiled(doWork);
+
+        // (3) Throw away reference to hiddenClass to allow unloading
+        hiddenClass = null;
+
+        // Force garbage collection to trigger unloading of hiddenClass
+        WHITE_BOX.fullGC();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/HiddenClasses/pkg/HasNamedModule.java	Tue Jan 07 13:49:31 2020 +0000
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2020, 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 pkg;
+
+import java.lang.invoke.MethodType;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*;
+
+// This class is used by test HiddenGetModule.java.
+public class HasNamedModule {
+
+    public static void compareModules(byte[] klassbuf) throws Throwable {
+        String moduleName = HasNamedModule.class.getModule().toString();
+        System.out.println("HasNamedModule module: " + moduleName);
+        Lookup lookup = MethodHandles.lookup();
+        Class<?> cl = lookup.defineHiddenClass(klassbuf, false, NESTMATE).lookupClass();
+        if (cl.getModule() != HasNamedModule.class.getModule()) {
+            System.out.println("HasNamedModule: " + moduleName +
+                               ", hidden class module: " + cl.getModule());
+            throw new RuntimeException("hidden class and lookup class have different modules");
+	}
+        if (!moduleName.contains("HiddenModule")) {
+            throw new RuntimeException("wrong module name: " + moduleName);
+        }
+    }
+}