--- old/src/hotspot/share/classfile/systemDictionary.cpp 2020-06-05 01:14:45.650560056 +0000 +++ new/src/hotspot/share/classfile/systemDictionary.cpp 2020-06-05 01:14:44.222525308 +0000 @@ -699,7 +699,7 @@ return NULL; } -static void post_class_load_event(EventClassLoad* event, const InstanceKlass* k, const ClassLoaderData* init_cld) { +void SystemDictionary::post_class_load_event(EventClassLoad* event, const InstanceKlass* k, const ClassLoaderData* init_cld) { assert(event != NULL, "invariant"); assert(k != NULL, "invariant"); assert(event->should_commit(), "invariant"); @@ -1375,7 +1375,6 @@ Handle class_loader, Handle protection_domain, PackageEntry* pkg_entry, - bool initialize, TRAPS) { InstanceKlass* shared_nest_host = SystemDictionaryShared::get_shared_nest_host(ik); assert(shared_nest_host->is_shared(), "nest host must be in CDS archive"); @@ -1400,28 +1399,6 @@ assert(shared_nest_host->is_same_class_package(ik), "lambda proxy class and its nest host must be in the same package"); - EventClassLoad class_load_start_event; - { - MutexLocker mu_r(THREAD, Compile_lock); - - // Add to class hierarchy, initialize vtables, and do possible - // deoptimizations. - SystemDictionary::add_to_hierarchy(loaded_ik, CHECK_NULL); // No exception, but can block - // But, do not add to dictionary. - } - loaded_ik->link_class(CHECK_NULL); - // notify jvmti - if (JvmtiExport::should_post_class_load()) { - assert(THREAD->is_Java_thread(), "thread->is_Java_thread()"); - JvmtiExport::post_class_load((JavaThread *) THREAD, loaded_ik); - } - if (class_load_start_event.should_commit()) { - post_class_load_event(&class_load_start_event, loaded_ik, ClassLoaderData::class_loader_data(class_loader())); - } - - if (initialize) { - loaded_ik->initialize(CHECK_NULL); - } return loaded_ik; } --- old/src/hotspot/share/classfile/systemDictionary.hpp 2020-06-05 01:14:49.116644396 +0000 +++ new/src/hotspot/share/classfile/systemDictionary.hpp 2020-06-05 01:14:47.692609745 +0000 @@ -131,6 +131,7 @@ class ProtectionDomainCacheTable; class ProtectionDomainCacheEntry; class GCTimer; +class EventClassLoad; #define WK_KLASS_ENUM_NAME(kname) kname##_knum @@ -610,6 +611,7 @@ static LoaderConstraintTable* constraints() { return _loader_constraints; } static ResolutionErrorTable* resolution_errors() { return _resolution_errors; } static SymbolPropertyTable* invoke_method_table() { return _invoke_method_table; } + static void post_class_load_event(EventClassLoad* event, const InstanceKlass* k, const ClassLoaderData* init_cld); // Basic loading operations static InstanceKlass* resolve_instance_class_or_null_helper(Symbol* name, @@ -640,7 +642,6 @@ Handle class_loader, Handle protection_domain, PackageEntry* pkg_entry, - bool initialize, TRAPS); static InstanceKlass* load_shared_class(InstanceKlass* ik, Handle class_loader, --- old/src/hotspot/share/classfile/systemDictionaryShared.cpp 2020-06-05 01:14:52.510726984 +0000 +++ new/src/hotspot/share/classfile/systemDictionaryShared.cpp 2020-06-05 01:14:51.088692382 +0000 @@ -36,6 +36,7 @@ #include "classfile/systemDictionaryShared.hpp" #include "classfile/verificationType.hpp" #include "classfile/vmSymbols.hpp" +#include "jfr/jfrEvents.hpp" #include "logging/log.hpp" #include "memory/allocation.hpp" #include "memory/archiveUtils.hpp" @@ -1667,9 +1668,9 @@ return record->nest_host(); } -InstanceKlass* SystemDictionaryShared::load_shared_lambda_proxy_class(InstanceKlass* lambda_ik, - InstanceKlass* caller_ik, - bool initialize, TRAPS) { +InstanceKlass* SystemDictionaryShared::prepare_shared_lambda_proxy_class(InstanceKlass* lambda_ik, + InstanceKlass* caller_ik, + bool initialize, TRAPS) { Handle class_loader(THREAD, caller_ik->class_loader()); Handle protection_domain; PackageEntry* pkg_entry = get_package_entry_from_class_name(class_loader, caller_ik->name()); @@ -1681,15 +1682,36 @@ assert(shared_nest_host != NULL, "unexpected NULL _nest_host"); InstanceKlass* loaded_lambda = - SystemDictionary::load_shared_lambda_proxy_class(lambda_ik, class_loader, protection_domain, pkg_entry, initialize, CHECK_NULL); + SystemDictionary::load_shared_lambda_proxy_class(lambda_ik, class_loader, protection_domain, pkg_entry, CHECK_NULL); - InstanceKlass* nest_host = caller_ik->nest_host(THREAD); - // The following ensures that the caller's nest host is the same as the lambda proxy's + // Ensures the nest host is the same as the lambda proxy's // nest host recorded at dump time. - assert(nest_host->has_nest_member(caller_ik, THREAD) || - nest_host == caller_ik, "caller_ik failed nest member check"); + InstanceKlass* nest_host = caller_ik->nest_host(THREAD); assert(nest_host == shared_nest_host, "mismatched nest host"); + EventClassLoad class_load_start_event; + { + MutexLocker mu_r(THREAD, Compile_lock); + + // Add to class hierarchy, initialize vtables, and do possible + // deoptimizations. + SystemDictionary::add_to_hierarchy(loaded_lambda, CHECK_NULL); // No exception, but can block + // But, do not add to dictionary. + } + loaded_lambda->link_class(CHECK_NULL); + // notify jvmti + if (JvmtiExport::should_post_class_load()) { + assert(THREAD->is_Java_thread(), "thread->is_Java_thread()"); + JvmtiExport::post_class_load((JavaThread *) THREAD, loaded_lambda); + } + if (class_load_start_event.should_commit()) { + SystemDictionary::post_class_load_event(&class_load_start_event, loaded_lambda, ClassLoaderData::class_loader_data(class_loader())); + } + + if (initialize) { + loaded_lambda->initialize(CHECK_NULL); + } + return loaded_lambda; } --- old/src/hotspot/share/classfile/systemDictionaryShared.hpp 2020-06-05 01:14:56.054813222 +0000 +++ new/src/hotspot/share/classfile/systemDictionaryShared.hpp 2020-06-05 01:14:54.519775870 +0000 @@ -304,9 +304,9 @@ Method* member_method, Symbol* instantiated_method_type) NOT_CDS_RETURN_(NULL); static InstanceKlass* get_shared_nest_host(InstanceKlass* lambda_ik) NOT_CDS_RETURN_(NULL); - static InstanceKlass* load_shared_lambda_proxy_class(InstanceKlass* lambda_ik, - InstanceKlass* caller_ik, - bool initialize, TRAPS) NOT_CDS_RETURN_(NULL); + static InstanceKlass* prepare_shared_lambda_proxy_class(InstanceKlass* lambda_ik, + InstanceKlass* caller_ik, + bool initialize, TRAPS) NOT_CDS_RETURN_(NULL); static bool check_linking_constraints(InstanceKlass* klass, TRAPS) NOT_CDS_RETURN_(false); static void record_linking_constraint(Symbol* name, InstanceKlass* klass, Handle loader1, Handle loader2, TRAPS) NOT_CDS_RETURN; --- old/src/hotspot/share/prims/jvm.cpp 2020-06-05 01:14:59.480896589 +0000 +++ new/src/hotspot/share/prims/jvm.cpp 2020-06-05 01:14:58.047861719 +0000 @@ -3709,6 +3709,12 @@ Klass* caller_k = java_lang_Class::as_Klass(JNIHandles::resolve(caller)); InstanceKlass* caller_ik = InstanceKlass::cast(caller_k); + if (caller_ik->is_hidden() || caller_ik->is_unsafe_anonymous()) { + // VM anonymous classes and hidden classes not of type lambda proxy classes are currently not being archived. + // If the caller_ik is of one of the above types, the corresponding lambda proxy class won't be + // registered for archiving. + return; + } Klass* lambda_k = java_lang_Class::as_Klass(JNIHandles::resolve(lambdaProxyClass)); InstanceKlass* lambda_ik = InstanceKlass::cast(lambda_k); assert(lambda_ik->is_hidden(), "must be a hidden class"); @@ -3751,7 +3757,7 @@ if (invokedName == NULL || invokedType == NULL || methodType == NULL || implMethodMember == NULL || instantiatedMethodType == NULL) { - return NULL; + THROW_(vmSymbols::java_lang_NullPointerException(), NULL); } Klass* caller_k = java_lang_Class::as_Klass(JNIHandles::resolve(caller)); @@ -3779,7 +3785,7 @@ method_type, m, instantiated_method_type); jclass jcls = NULL; if (lambda_ik != NULL) { - InstanceKlass* loaded_lambda = SystemDictionaryShared::load_shared_lambda_proxy_class(lambda_ik, caller_ik, initialize, THREAD); + InstanceKlass* loaded_lambda = SystemDictionaryShared::prepare_shared_lambda_proxy_class(lambda_ik, caller_ik, initialize, THREAD); jcls = loaded_lambda == NULL ? NULL : (jclass) JNIHandles::make_local(env, loaded_lambda->java_mirror()); } return jcls; --- /dev/null 2019-10-31 15:42:43.283000000 +0000 +++ new/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/LambdaProxyCallerIsHidden.java 2020-06-05 01:15:01.501945767 +0000 @@ -0,0 +1,73 @@ +/* + * 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 If the caller class of a lambda proxy class is a hidden class, + * the lambda proxy class will not be archived. + * @requires vm.cds + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds + * /test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes + * @modules java.base/jdk.internal.misc + * @compile test-classes/LambdaProxyCallerIsHiddenApp.java + * ../../../../../../lib/jdk/test/lib/compiler/InMemoryJavaCompiler.java + * @build sun.hotspot.WhiteBox + * @run driver ClassFileInstaller -jar callerishidden.jar LambdaProxyCallerIsHiddenApp + * jdk/test/lib/compiler/InMemoryJavaCompiler + * jdk/test/lib/compiler/InMemoryJavaCompiler$FileManagerWrapper$1 + * jdk/test/lib/compiler/InMemoryJavaCompiler$FileManagerWrapper + * jdk/test/lib/compiler/InMemoryJavaCompiler$MemoryJavaFileObject + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. LambdaProxyCallerIsHidden + */ + +public class LambdaProxyCallerIsHidden extends DynamicArchiveTestBase { + public static void main(String[] args) throws Exception { + runTest(LambdaProxyCallerIsHidden::test); + } + + static void test() throws Exception { + String topArchiveName = getNewArchiveName(); + String appJar = ClassFileInstaller.getJarPath("callerishidden.jar"); + String mainClass = "LambdaProxyCallerIsHiddenApp"; + + dump(topArchiveName, + "-Xlog:class+load,cds+dynamic,cds", + "-cp", appJar, mainClass) + .assertNormalExit(output -> { + output.shouldMatch("Skipping.LambdaHello_0x.*[$][$]Lambda[$].*:.Hidden.class") + .shouldMatch("Skipping.LambdaHello.0x.*:.Hidden.class") + .shouldHaveExitValue(0); + }); + + run(topArchiveName, + "-Xlog:class+load,cds+dynamic,cds", + "-cp", appJar, mainClass) + .assertNormalExit(output -> { + output.shouldMatch("class.load.*LambdaHello/0x.*source.*LambdaProxyCallerIsHiddenApp") + .shouldMatch("class.load.*LambdaHello_0x.*[$][$]Lambda[$].*source.*LambdaProxyCallerIsHiddenApp") + .shouldHaveExitValue(0); + }); + } +} --- /dev/null 2019-10-31 15:42:43.283000000 +0000 +++ new/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/UnsafeAndLambda.java 2020-06-05 01:15:05.224036336 +0000 @@ -0,0 +1,74 @@ +/* + * 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 LambdaMetafactory does not support VM anonymous classes. + * This is a sanity test to make sure CDS can handle this case and + * the VM anonymous class should not be archived. + * @requires vm.cds + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds + * /test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes + * @modules java.base/jdk.internal.misc + * @compile test-classes/UnsafeAndLambdaApp.java + * ../../../../../../lib/jdk/test/lib/compiler/InMemoryJavaCompiler.java + * @build sun.hotspot.WhiteBox + * @run driver ClassFileInstaller -jar unsafeandlambda.jar UnsafeAndLambdaApp + * jdk/test/lib/compiler/InMemoryJavaCompiler + * jdk/test/lib/compiler/InMemoryJavaCompiler$FileManagerWrapper$1 + * jdk/test/lib/compiler/InMemoryJavaCompiler$FileManagerWrapper + * jdk/test/lib/compiler/InMemoryJavaCompiler$MemoryJavaFileObject + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. UnsafeAndLambda + */ + +public class UnsafeAndLambda extends DynamicArchiveTestBase { + public static void main(String[] args) throws Exception { + runTest(UnsafeAndLambda::test); + } + + static void test() throws Exception { + String topArchiveName = getNewArchiveName(); + String appJar = ClassFileInstaller.getJarPath("unsafeandlambda.jar"); + String mainClass = "UnsafeAndLambdaApp"; + + dump(topArchiveName, + "-Xlog:class+load=debug,cds+dynamic,cds", + "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", + "-cp", appJar, mainClass) + .assertNormalExit(output -> { + output.shouldContain("Skipping LambdaHello: Unsafe anonymous class") + .shouldHaveExitValue(0); + }); + + run(topArchiveName, + "-Xlog:class+load=debug,cds+dynamic,cds", + "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", + "-cp", appJar, mainClass) + .assertNormalExit(output -> { + output.shouldMatch("class.load.*LambdaHello/0x.*source.*UnsafeAndLambdaApp") + .shouldHaveExitValue(0); + }); + } +} --- /dev/null 2019-10-31 15:42:43.283000000 +0000 +++ new/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/LambdaProxyCallerIsHiddenApp.java 2020-06-05 01:15:08.888125494 +0000 @@ -0,0 +1,53 @@ +/* + * 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. + * + */ + +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; +import jdk.internal.misc.Unsafe; + +public class LambdaProxyCallerIsHiddenApp { + + static byte klassbuf[] = InMemoryJavaCompiler.compile("LambdaHello", + "public class LambdaHello { " + + " static Runnable run; " + + " static { " + + " run = LambdaHello::myrun; " + + " } " + + " static void myrun() { " + + " System.out.println(\"Hello\"); " + + " } " + + "} "); + + public static void main(String args[]) throws Exception { + Lookup lookup = MethodHandles.lookup(); + System.out.println("lookup: " + lookup); + + Class hiddenClass = lookup.defineHiddenClass(klassbuf, true, NESTMATE, STRONG).lookupClass(); + System.out.println("hiddenClass: " + hiddenClass); + Object o = hiddenClass.newInstance(); + System.out.println("o: " + o); + } +} --- /dev/null 2019-10-31 15:42:43.283000000 +0000 +++ new/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/UnsafeAndLambdaApp.java 2020-06-05 01:15:12.525213995 +0000 @@ -0,0 +1,54 @@ +/* + * 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. + * + */ +import jdk.test.lib.compiler.InMemoryJavaCompiler; +import jdk.internal.misc.Unsafe; + +public class UnsafeAndLambdaApp { + + static byte klassbuf[] = InMemoryJavaCompiler.compile("LambdaHello", + "public class LambdaHello { " + + " public LambdaHello() { " + + " doit(() -> { " + + " System.out.println(\"Hello from Lambda\"); " + + " }); " + + " } " + + " static void doit (Runnable r) { " + + " r.run(); " + + " } " + + "} "); + + public static void main(String args[]) throws Exception { + Unsafe unsafe = Unsafe.getUnsafe(); + + Class klass = unsafe.defineAnonymousClass(UnsafeAndLambdaApp.class, klassbuf, new Object[0]); + try { + Object obj = klass.newInstance(); + // If we come to here, LambdaMetafactory has probably been modified + // to support vm-anon classes. In that case, we will need more tests for CDS. + throw new RuntimeException("Unexpected support for lambda classes in VM anonymous classes"); + } catch (java.lang.InternalError expected) { + System.out.println("Caught expected java.lang.InternalError"); + } + } +}