8280767: -XX:ArchiveClassesAtExit does not archive BoundMethodHandle$Species classes
Reviewed-by: iklam, ccheung
This commit is contained in:
parent
f5d6fddc6d
commit
8e4ef818a9
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2022, 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
|
||||
@ -67,12 +67,6 @@ static bool should_be_archived(char* line) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void LambdaFormInvokers::append_filtered(char* line) {
|
||||
if (should_be_archived(line)) {
|
||||
append(line);
|
||||
}
|
||||
}
|
||||
#undef NUM_FILTER
|
||||
|
||||
void LambdaFormInvokers::append(char* line) {
|
||||
@ -180,6 +174,15 @@ void LambdaFormInvokers::regenerate_holder_classes(TRAPS) {
|
||||
}
|
||||
}
|
||||
|
||||
// check if a class name is a species
|
||||
bool is_a_species(const char* species_name) {
|
||||
log_info(cds)("Checking class %s", species_name);
|
||||
if (strstr(species_name, "java/lang/invoke/BoundMethodHandle$Species_") != nullptr) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void LambdaFormInvokers::regenerate_class(char* name, ClassFileStream& st, TRAPS) {
|
||||
Symbol* class_name = SymbolTable::new_symbol((const char*)name);
|
||||
// the class must exist
|
||||
@ -188,6 +191,12 @@ void LambdaFormInvokers::regenerate_class(char* name, ClassFileStream& st, TRAPS
|
||||
log_info(cds)("Class %s not present, skip", name);
|
||||
return;
|
||||
}
|
||||
// the species is shared in base archive, skip it.
|
||||
if (klass->is_regenerated() && is_a_species(name)) {
|
||||
log_info(cds)("Skip regenerating for shared %s", name);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(klass->is_instance_klass(), "Should be");
|
||||
|
||||
ClassLoaderData* cld = ClassLoaderData::the_null_class_loader_data();
|
||||
@ -211,8 +220,8 @@ void LambdaFormInvokers::regenerate_class(char* name, ClassFileStream& st, TRAPS
|
||||
MetaspaceShared::try_link_class(THREAD, result);
|
||||
assert(!HAS_PENDING_EXCEPTION, "Invariant");
|
||||
|
||||
// exclude the existing class from dump
|
||||
SystemDictionaryShared::set_excluded(InstanceKlass::cast(klass));
|
||||
result->set_regenerated(); // mark for regenerated
|
||||
SystemDictionaryShared::set_excluded(InstanceKlass::cast(klass)); // exclude the existing class from dump
|
||||
SystemDictionaryShared::init_dumptime_info(result);
|
||||
log_info(cds, lambda)("Regenerated class %s, old: " INTPTR_FORMAT " new: " INTPTR_FORMAT,
|
||||
name, p2i(klass), p2i(result));
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2022, 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
|
||||
@ -43,7 +43,6 @@ class LambdaFormInvokers : public AllStatic {
|
||||
static void add_regenerated_class(oop regenerated_class);
|
||||
public:
|
||||
static void append(char* line);
|
||||
static void append_filtered(char* line);
|
||||
static void dump_static_archive_invokers();
|
||||
static void read_static_archive_invokers();
|
||||
static void regenerate_holder_classes(TRAPS);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2022, 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
|
||||
@ -1415,6 +1415,11 @@ InstanceKlass* SystemDictionaryShared::find_builtin_class(Symbol* name) {
|
||||
if (record != NULL) {
|
||||
assert(!record->_klass->is_hidden(), "hidden class cannot be looked up by name");
|
||||
assert(check_alignment(record->_klass), "Address not aligned");
|
||||
// We did not save the classfile data of the regenerated LambdaForm invoker classes,
|
||||
// so we cannot support CLFH for such classes.
|
||||
if (record->_klass->is_regenerated() && JvmtiExport::should_post_class_file_load_hook()) {
|
||||
return NULL;
|
||||
}
|
||||
return record->_klass;
|
||||
} else {
|
||||
return NULL;
|
||||
|
@ -175,7 +175,8 @@ private:
|
||||
enum {
|
||||
_archived_lambda_proxy_is_available = 2,
|
||||
_has_value_based_class_annotation = 4,
|
||||
_verified_at_dump_time = 8
|
||||
_verified_at_dump_time = 8,
|
||||
_regenerated = 16
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -339,6 +340,13 @@ protected:
|
||||
NOT_CDS(return false;)
|
||||
}
|
||||
|
||||
void set_regenerated() {
|
||||
CDS_ONLY(_shared_class_flags |= _regenerated;)
|
||||
}
|
||||
bool is_regenerated() const {
|
||||
CDS_ONLY(return (_shared_class_flags & _regenerated) != 0;)
|
||||
NOT_CDS(return false;)
|
||||
}
|
||||
|
||||
// Obtain the module or package for this class
|
||||
virtual ModuleEntry* module() const = 0;
|
||||
|
@ -3689,9 +3689,9 @@ JVM_ENTRY(void, JVM_LogLambdaFormInvoker(JNIEnv *env, jstring line))
|
||||
Handle h_line (THREAD, JNIHandles::resolve_non_null(line));
|
||||
char* c_line = java_lang_String::as_utf8_string(h_line());
|
||||
if (DynamicDumpSharedSpaces) {
|
||||
// Note: LambdaFormInvokers::append_filtered and LambdaFormInvokers::append take same format which is not
|
||||
// Note: LambdaFormInvokers::append take same format which is not
|
||||
// same as below the print format. The line does not include LAMBDA_FORM_TAG.
|
||||
LambdaFormInvokers::append_filtered(os::strdup((const char*)c_line, mtInternal));
|
||||
LambdaFormInvokers::append(os::strdup((const char*)c_line, mtInternal));
|
||||
}
|
||||
if (ClassListWriter::is_enabled()) {
|
||||
ClassListWriter w;
|
||||
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
|
||||
public class CDSLambdaInvoker {
|
||||
public static void main(String args[]) throws Throwable {
|
||||
invoke(MethodHandles.identity(double.class), 1.0);
|
||||
invoke(MethodHandles.identity(long.class), 1);
|
||||
invoke(MethodHandles.identity(int.class), 1);
|
||||
invoke(MethodHandles.identity(float.class), 1.0f);
|
||||
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
MethodType mt = MethodType.methodType(void.class, float.class, double.class, int.class,
|
||||
boolean.class, Object.class, long.class, double.class);
|
||||
MethodHandle mh = lookup.findStatic(CDSLambdaInvoker.class, "callme", mt);
|
||||
mh.invokeExact(4.0f, 5.0, 6, true, (Object)args, 7L, 8.0);
|
||||
}
|
||||
|
||||
private static Object invoke(MethodHandle mh, Object ... args) throws Throwable {
|
||||
try {
|
||||
for (Object o : args) {
|
||||
mh = MethodHandles.insertArguments(mh, 0, o);
|
||||
}
|
||||
return mh.invoke();
|
||||
} catch (Throwable t) {
|
||||
System.out.println("Failed to find, link and/or invoke " + mh.toString() + ": " + t.getMessage());
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
private static void callme(float f, double d, int i, boolean b, Object o, long l, double d2) {
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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
|
||||
* @key randomness
|
||||
* @summary test archive lambda invoker species type in dynamic dump
|
||||
* @bug 8280767
|
||||
* @requires vm.cds
|
||||
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds /test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive
|
||||
* @compile CDSLambdaInvoker.java
|
||||
* @build sun.hotspot.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar cds-test.jar CDSLambdaInvoker
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox
|
||||
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. TestLambdaInvokers
|
||||
*/
|
||||
|
||||
public class TestLambdaInvokers extends DynamicArchiveTestBase {
|
||||
private static final String mainClass = "CDSLambdaInvoker";
|
||||
private static final String jarFile = "cds-test.jar";
|
||||
private static void doTest(String topArchiveName) throws Exception {
|
||||
dump(topArchiveName,
|
||||
"-Xlog:cds",
|
||||
"-Xlog:cds+dynamic=debug",
|
||||
"-cp",
|
||||
jarFile,
|
||||
mainClass)
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldContain("Skip regenerating for shared");
|
||||
});
|
||||
run(topArchiveName,
|
||||
"-Xlog:cds",
|
||||
"-Xlog:cds+dynamic=debug",
|
||||
"-Xlog:class+load",
|
||||
"-cp",
|
||||
jarFile,
|
||||
mainClass)
|
||||
.assertNormalExit(output -> {
|
||||
// java.lang.invoke.BoundMethodHandle$Species_JL is generated from CDSLambdaInvoker
|
||||
output.shouldContain("java.lang.invoke.BoundMethodHandle$Species_JL source: shared objects file (top)");
|
||||
});
|
||||
}
|
||||
|
||||
static void testWithDefaultBase() throws Exception {
|
||||
String topArchiveName = getNewArchiveName("top");
|
||||
doTest(topArchiveName);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
runTest(TestLambdaInvokers::testWithDefaultBase);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user