8247536: Support for pre-generated java.lang.invoke classes in CDS static archive
Reviewed-by: iklam, mchung
This commit is contained in:
parent
7ec9c8eac7
commit
e4469d2c8c
@ -126,6 +126,7 @@ ifneq ($(call check-jvm-feature, cds), true)
|
|||||||
dynamicArchive.cpp \
|
dynamicArchive.cpp \
|
||||||
filemap.cpp \
|
filemap.cpp \
|
||||||
heapShared.cpp \
|
heapShared.cpp \
|
||||||
|
lambdaFormInvokers.cpp \
|
||||||
metaspaceShared.cpp \
|
metaspaceShared.cpp \
|
||||||
metaspaceShared_$(HOTSPOT_TARGET_CPU).cpp \
|
metaspaceShared_$(HOTSPOT_TARGET_CPU).cpp \
|
||||||
metaspaceShared_$(HOTSPOT_TARGET_CPU_ARCH).cpp \
|
metaspaceShared_$(HOTSPOT_TARGET_CPU_ARCH).cpp \
|
||||||
|
@ -146,6 +146,7 @@ JVM_IsArrayClass
|
|||||||
JVM_IsDynamicDumpingEnabled
|
JVM_IsDynamicDumpingEnabled
|
||||||
JVM_IsSharingEnabled
|
JVM_IsSharingEnabled
|
||||||
JVM_IsConstructorIx
|
JVM_IsConstructorIx
|
||||||
|
JVM_IsDumpingClassList
|
||||||
JVM_IsHiddenClass
|
JVM_IsHiddenClass
|
||||||
JVM_IsInterface
|
JVM_IsInterface
|
||||||
JVM_IsPrimitiveClass
|
JVM_IsPrimitiveClass
|
||||||
@ -158,6 +159,7 @@ JVM_LatestUserDefinedLoader
|
|||||||
JVM_LoadLibrary
|
JVM_LoadLibrary
|
||||||
JVM_LookupDefineClass
|
JVM_LookupDefineClass
|
||||||
JVM_LookupLambdaProxyClassFromArchive
|
JVM_LookupLambdaProxyClassFromArchive
|
||||||
|
JVM_LogLambdaFormInvoker
|
||||||
JVM_MaxMemory
|
JVM_MaxMemory
|
||||||
JVM_MaxObjectInspectionAge
|
JVM_MaxObjectInspectionAge
|
||||||
JVM_MonitorNotify
|
JVM_MonitorNotify
|
||||||
|
@ -6056,7 +6056,18 @@ void ClassFileParser::mangle_hidden_class_name(InstanceKlass* const ik) {
|
|||||||
// use an illegal char such as ';' because that causes serialization issues
|
// use an illegal char such as ';' because that causes serialization issues
|
||||||
// and issues with hidden classes that create their own hidden classes.
|
// and issues with hidden classes that create their own hidden classes.
|
||||||
char addr_buf[20];
|
char addr_buf[20];
|
||||||
|
if (DumpSharedSpaces) {
|
||||||
|
// We want stable names for the archived hidden classes (only for static
|
||||||
|
// archive for now). Spaces under default_SharedBaseAddress() will be
|
||||||
|
// occupied by the archive at run time, so we know that no dynamically
|
||||||
|
// loaded InstanceKlass will be placed under there.
|
||||||
|
static volatile size_t counter = 0;
|
||||||
|
Atomic::cmpxchg(&counter, (size_t)0, Arguments::default_SharedBaseAddress()); // initialize it
|
||||||
|
size_t new_id = Atomic::add(&counter, (size_t)1);
|
||||||
|
jio_snprintf(addr_buf, 20, SIZE_FORMAT_HEX, new_id);
|
||||||
|
} else {
|
||||||
jio_snprintf(addr_buf, 20, INTPTR_FORMAT, p2i(ik));
|
jio_snprintf(addr_buf, 20, INTPTR_FORMAT, p2i(ik));
|
||||||
|
}
|
||||||
size_t new_name_len = _class_name->utf8_length() + 2 + strlen(addr_buf);
|
size_t new_name_len = _class_name->utf8_length() + 2 + strlen(addr_buf);
|
||||||
char* new_name = NEW_RESOURCE_ARRAY(char, new_name_len);
|
char* new_name = NEW_RESOURCE_ARRAY(char, new_name_len);
|
||||||
jio_snprintf(new_name, new_name_len, "%s+%s",
|
jio_snprintf(new_name, new_name_len, "%s+%s",
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "classfile/classListParser.hpp"
|
#include "classfile/classListParser.hpp"
|
||||||
#include "classfile/classLoaderExt.hpp"
|
#include "classfile/classLoaderExt.hpp"
|
||||||
#include "classfile/javaClasses.inline.hpp"
|
#include "classfile/javaClasses.inline.hpp"
|
||||||
|
#include "classfile/lambdaFormInvokers.hpp"
|
||||||
#include "classfile/symbolTable.hpp"
|
#include "classfile/symbolTable.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
#include "classfile/systemDictionaryShared.hpp"
|
#include "classfile/systemDictionaryShared.hpp"
|
||||||
@ -86,6 +87,12 @@ bool ClassListParser::parse_one_line() {
|
|||||||
if (*_line == '#') { // comment
|
if (*_line == '#') { // comment
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// The line is output TRACE_RESOLVE
|
||||||
|
if (strncmp(_line, LambdaFormInvokers::lambda_form_invoker_tag(),
|
||||||
|
strlen(LambdaFormInvokers::lambda_form_invoker_tag())) == 0) {
|
||||||
|
LambdaFormInvokers::append(os::strdup((const char*)_line, mtInternal));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1244,6 +1244,8 @@ oop java_lang_Class::process_archived_mirror(Klass* k, oop mirror,
|
|||||||
java_lang_Class:set_init_lock(archived_mirror, NULL);
|
java_lang_Class:set_init_lock(archived_mirror, NULL);
|
||||||
|
|
||||||
set_protection_domain(archived_mirror, NULL);
|
set_protection_domain(archived_mirror, NULL);
|
||||||
|
set_signers(archived_mirror, NULL);
|
||||||
|
set_source_file(archived_mirror, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear class loader and mirror_module_field
|
// clear class loader and mirror_module_field
|
||||||
|
@ -31,11 +31,7 @@
|
|||||||
class ClassFileStream;
|
class ClassFileStream;
|
||||||
class ClassLoaderData;
|
class ClassLoaderData;
|
||||||
class ClassLoadInfo;
|
class ClassLoadInfo;
|
||||||
template <typename>
|
|
||||||
class GrowableArray;
|
|
||||||
class Klass;
|
|
||||||
class Symbol;
|
class Symbol;
|
||||||
class TempNewSymbol;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* KlassFactory is an interface to implementations of the following mapping/function:
|
* KlassFactory is an interface to implementations of the following mapping/function:
|
||||||
@ -63,18 +59,12 @@ class TempNewSymbol;
|
|||||||
|
|
||||||
class KlassFactory : AllStatic {
|
class KlassFactory : AllStatic {
|
||||||
|
|
||||||
// approved clients
|
public:
|
||||||
friend class ClassLoader;
|
|
||||||
friend class ClassLoaderExt;
|
|
||||||
friend class SystemDictionary;
|
|
||||||
|
|
||||||
private:
|
|
||||||
static InstanceKlass* create_from_stream(ClassFileStream* stream,
|
static InstanceKlass* create_from_stream(ClassFileStream* stream,
|
||||||
Symbol* name,
|
Symbol* name,
|
||||||
ClassLoaderData* loader_data,
|
ClassLoaderData* loader_data,
|
||||||
const ClassLoadInfo& cl_info,
|
const ClassLoadInfo& cl_info,
|
||||||
TRAPS);
|
TRAPS);
|
||||||
public:
|
|
||||||
static InstanceKlass* check_shared_class_file_load_hook(
|
static InstanceKlass* check_shared_class_file_load_hook(
|
||||||
InstanceKlass* ik,
|
InstanceKlass* ik,
|
||||||
Symbol* class_name,
|
Symbol* class_name,
|
||||||
|
153
src/hotspot/share/classfile/lambdaFormInvokers.cpp
Normal file
153
src/hotspot/share/classfile/lambdaFormInvokers.cpp
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "precompiled.hpp"
|
||||||
|
#include "classfile/classLoadInfo.hpp"
|
||||||
|
#include "classfile/classFileStream.hpp"
|
||||||
|
#include "classfile/dictionary.hpp"
|
||||||
|
#include "classfile/javaClasses.inline.hpp"
|
||||||
|
#include "classfile/klassFactory.hpp"
|
||||||
|
#include "classfile/lambdaFormInvokers.hpp"
|
||||||
|
#include "classfile/symbolTable.hpp"
|
||||||
|
#include "classfile/systemDictionary.hpp"
|
||||||
|
#include "classfile/systemDictionaryShared.hpp"
|
||||||
|
#include "classfile/vmSymbols.hpp"
|
||||||
|
#include "logging/log.hpp"
|
||||||
|
#include "memory/oopFactory.hpp"
|
||||||
|
#include "memory/metaspaceShared.hpp"
|
||||||
|
#include "memory/resourceArea.hpp"
|
||||||
|
#include "oops/instanceKlass.hpp"
|
||||||
|
#include "oops/klass.hpp"
|
||||||
|
#include "oops/objArrayKlass.hpp"
|
||||||
|
#include "oops/objArrayOop.hpp"
|
||||||
|
#include "oops/oop.inline.hpp"
|
||||||
|
#include "oops/typeArrayOop.inline.hpp"
|
||||||
|
#include "runtime/handles.inline.hpp"
|
||||||
|
#include "runtime/javaCalls.hpp"
|
||||||
|
|
||||||
|
GrowableArray<char*>* LambdaFormInvokers::_lambdaform_lines = NULL;
|
||||||
|
|
||||||
|
void LambdaFormInvokers::append(char* line) {
|
||||||
|
if (_lambdaform_lines == NULL) {
|
||||||
|
_lambdaform_lines = new GrowableArray<char*>(100);
|
||||||
|
}
|
||||||
|
_lambdaform_lines->append(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LambdaFormInvokers::regenerate_holder_classes(TRAPS) {
|
||||||
|
assert(_lambdaform_lines != NULL, "Bad List");
|
||||||
|
ResourceMark rm(THREAD);
|
||||||
|
|
||||||
|
Symbol* cds_name = vmSymbols::jdk_internal_misc_CDS();
|
||||||
|
Klass* cds_klass = SystemDictionary::resolve_or_null(cds_name, THREAD);
|
||||||
|
guarantee(cds_klass != NULL, "jdk/internal/misc/CDS must exist!");
|
||||||
|
|
||||||
|
int len = _lambdaform_lines->length();
|
||||||
|
objArrayHandle list_lines = oopFactory::new_objArray_handle(SystemDictionary::String_klass(), len, CHECK);
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
char* record = _lambdaform_lines->at(i);
|
||||||
|
record += strlen(lambda_form_invoker_tag()) + 1; // skip the @lambda_form_invoker prefix
|
||||||
|
Handle h_line = java_lang_String::create_from_str(record, CHECK);
|
||||||
|
list_lines->obj_at_put(i, h_line());
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Object[] CDS.generateLambdaFormHolderClasses(String[] lines)
|
||||||
|
// the returned Object[] layout:
|
||||||
|
// name, byte[], name, byte[] ....
|
||||||
|
Symbol* method = vmSymbols::generateLambdaFormHolderClasses();
|
||||||
|
Symbol* signrs = vmSymbols::generateLambdaFormHolderClasses_signature();
|
||||||
|
|
||||||
|
JavaValue result(T_OBJECT);
|
||||||
|
JavaCalls::call_static(&result, cds_klass, method, signrs, list_lines, THREAD);
|
||||||
|
|
||||||
|
if (HAS_PENDING_EXCEPTION) {
|
||||||
|
log_info(cds)("%s: %s", THREAD->pending_exception()->klass()->external_name(),
|
||||||
|
java_lang_String::as_utf8_string(java_lang_Throwable::message(THREAD->pending_exception())));
|
||||||
|
CLEAR_PENDING_EXCEPTION;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
objArrayHandle h_array(THREAD, (objArrayOop)result.get_jobject());
|
||||||
|
int sz = h_array->length();
|
||||||
|
assert(sz % 2 == 0 && sz >= 2, "Must be even size of length");
|
||||||
|
for (int i = 0; i < sz; i+= 2) {
|
||||||
|
Handle h_name(THREAD, h_array->obj_at(i));
|
||||||
|
typeArrayHandle h_bytes(THREAD, (typeArrayOop)h_array->obj_at(i+1));
|
||||||
|
assert(h_name != NULL, "Class name is NULL");
|
||||||
|
assert(h_bytes != NULL, "Class bytes is NULL");
|
||||||
|
|
||||||
|
char *class_name = java_lang_String::as_utf8_string(h_name());
|
||||||
|
int len = h_bytes->length();
|
||||||
|
// make a copy of class bytes so GC will not affect us.
|
||||||
|
char *buf = resource_allocate_bytes(THREAD, len);
|
||||||
|
memcpy(buf, (char*)h_bytes->byte_at_addr(0), len);
|
||||||
|
ClassFileStream st((u1*)buf, len, NULL, ClassFileStream::verify);
|
||||||
|
|
||||||
|
reload_class(class_name, st, THREAD);
|
||||||
|
// free buf
|
||||||
|
resource_free_bytes(buf, len);
|
||||||
|
|
||||||
|
if (HAS_PENDING_EXCEPTION) {
|
||||||
|
log_info(cds)("Exception happened: %s", PENDING_EXCEPTION->klass()->name()->as_C_string());
|
||||||
|
log_info(cds)("Could not create InstanceKlass for class %s", class_name);
|
||||||
|
CLEAR_PENDING_EXCEPTION;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// class_handle - the class name, bytes_handle - the class bytes
|
||||||
|
void LambdaFormInvokers::reload_class(char* name, ClassFileStream& st, TRAPS) {
|
||||||
|
Symbol* class_name = SymbolTable::new_symbol((const char*)name);
|
||||||
|
// the class must exist
|
||||||
|
Klass* klass = SystemDictionary::resolve_or_null(class_name, THREAD);
|
||||||
|
if (klass == NULL) {
|
||||||
|
log_info(cds)("Class %s not present, skip", name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assert(klass->is_instance_klass(), "Should be");
|
||||||
|
|
||||||
|
ClassLoaderData* cld = ClassLoaderData::the_null_class_loader_data();
|
||||||
|
Handle protection_domain;
|
||||||
|
ClassLoadInfo cl_info(protection_domain);
|
||||||
|
|
||||||
|
InstanceKlass* result = KlassFactory::create_from_stream(&st,
|
||||||
|
class_name,
|
||||||
|
cld,
|
||||||
|
cl_info,
|
||||||
|
CHECK);
|
||||||
|
|
||||||
|
{
|
||||||
|
MutexLocker mu_r(THREAD, Compile_lock); // add_to_hierarchy asserts this.
|
||||||
|
SystemDictionary::add_to_hierarchy(result, THREAD);
|
||||||
|
}
|
||||||
|
// new class not linked yet.
|
||||||
|
MetaspaceShared::try_link_class(result, THREAD);
|
||||||
|
assert(!HAS_PENDING_EXCEPTION, "Invariant");
|
||||||
|
|
||||||
|
// exclude the existing class from dump
|
||||||
|
SystemDictionaryShared::set_excluded(InstanceKlass::cast(klass));
|
||||||
|
log_info(cds)("Replaced class %s, old: %p new: %p", name, klass, result);
|
||||||
|
}
|
50
src/hotspot/share/classfile/lambdaFormInvokers.hpp
Normal file
50
src/hotspot/share/classfile/lambdaFormInvokers.hpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SHARE_MEMORY_LAMBDAFORMINVOKERS_HPP
|
||||||
|
#define SHARE_MEMORY_LAMBDAFORMINVOKERS_HPP
|
||||||
|
#include "memory/allStatic.hpp"
|
||||||
|
#include "runtime/handles.hpp"
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class GrowableArray;
|
||||||
|
class ClassFileStream;
|
||||||
|
|
||||||
|
class LambdaFormInvokers : public AllStatic {
|
||||||
|
private:
|
||||||
|
static GrowableArray<char*>* _lambdaform_lines;
|
||||||
|
static void reload_class(char* name, ClassFileStream& st, TRAPS);
|
||||||
|
public:
|
||||||
|
|
||||||
|
static void append(char* line);
|
||||||
|
static void regenerate_holder_classes(TRAPS);
|
||||||
|
static GrowableArray<char*>* lambdaform_lines() {
|
||||||
|
return _lambdaform_lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* lambda_form_invoker_tag() {
|
||||||
|
return "@lambda-form-invoker";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif // SHARE_MEMORY_LAMBDAFORMINVOKERS_HPP
|
@ -624,9 +624,9 @@ public:
|
|||||||
// Return Symbol or throw exception if name given is can not be a valid Symbol.
|
// Return Symbol or throw exception if name given is can not be a valid Symbol.
|
||||||
static Symbol* class_name_symbol(const char* name, Symbol* exception, TRAPS);
|
static Symbol* class_name_symbol(const char* name, Symbol* exception, TRAPS);
|
||||||
|
|
||||||
protected:
|
|
||||||
// Setup link to hierarchy
|
// Setup link to hierarchy
|
||||||
static void add_to_hierarchy(InstanceKlass* k, TRAPS);
|
static void add_to_hierarchy(InstanceKlass* k, TRAPS);
|
||||||
|
protected:
|
||||||
|
|
||||||
// Basic find on loaded classes
|
// Basic find on loaded classes
|
||||||
static InstanceKlass* find_class(unsigned int hash,
|
static InstanceKlass* find_class(unsigned int hash,
|
||||||
|
@ -1407,6 +1407,14 @@ bool SystemDictionaryShared::is_excluded_class(InstanceKlass* k) {
|
|||||||
return (p == NULL) ? true : p->is_excluded();
|
return (p == NULL) ? true : p->is_excluded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SystemDictionaryShared::set_excluded(InstanceKlass* k) {
|
||||||
|
Arguments::assert_is_dumping_archive();
|
||||||
|
DumpTimeSharedClassInfo* info = find_or_allocate_info_for(k);
|
||||||
|
if (info != NULL) {
|
||||||
|
info->set_excluded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SystemDictionaryShared::set_class_has_failed_verification(InstanceKlass* ik) {
|
void SystemDictionaryShared::set_class_has_failed_verification(InstanceKlass* ik) {
|
||||||
Arguments::assert_is_dumping_archive();
|
Arguments::assert_is_dumping_archive();
|
||||||
DumpTimeSharedClassInfo* p = find_or_allocate_info_for(ik);
|
DumpTimeSharedClassInfo* p = find_or_allocate_info_for(ik);
|
||||||
|
@ -308,6 +308,7 @@ public:
|
|||||||
static void check_excluded_classes();
|
static void check_excluded_classes();
|
||||||
static void validate_before_archiving(InstanceKlass* k);
|
static void validate_before_archiving(InstanceKlass* k);
|
||||||
static bool is_excluded_class(InstanceKlass* k);
|
static bool is_excluded_class(InstanceKlass* k);
|
||||||
|
static void set_excluded(InstanceKlass* k);
|
||||||
static void dumptime_classes_do(class MetaspaceClosure* it);
|
static void dumptime_classes_do(class MetaspaceClosure* it);
|
||||||
static size_t estimate_size_for_archive();
|
static size_t estimate_size_for_archive();
|
||||||
static void write_to_archive(bool is_static_archive = true);
|
static void write_to_archive(bool is_static_archive = true);
|
||||||
|
@ -282,6 +282,10 @@
|
|||||||
template(base_name, "base") \
|
template(base_name, "base") \
|
||||||
/* Type Annotations (JDK 8 and above) */ \
|
/* Type Annotations (JDK 8 and above) */ \
|
||||||
template(type_annotations_name, "typeAnnotations") \
|
template(type_annotations_name, "typeAnnotations") \
|
||||||
|
/* used by CDS */ \
|
||||||
|
template(jdk_internal_misc_CDS, "jdk/internal/misc/CDS") \
|
||||||
|
template(generateLambdaFormHolderClasses, "generateLambdaFormHolderClasses") \
|
||||||
|
template(generateLambdaFormHolderClasses_signature, "([Ljava/lang/String;)[Ljava/lang/Object;") \
|
||||||
\
|
\
|
||||||
/* Intrinsic Annotation (JDK 9 and above) */ \
|
/* Intrinsic Annotation (JDK 9 and above) */ \
|
||||||
template(jdk_internal_vm_annotation_DontInline_signature, "Ljdk/internal/vm/annotation/DontInline;") \
|
template(jdk_internal_vm_annotation_DontInline_signature, "Ljdk/internal/vm/annotation/DontInline;") \
|
||||||
@ -289,7 +293,6 @@
|
|||||||
template(jdk_internal_vm_annotation_Hidden_signature, "Ljdk/internal/vm/annotation/Hidden;") \
|
template(jdk_internal_vm_annotation_Hidden_signature, "Ljdk/internal/vm/annotation/Hidden;") \
|
||||||
template(jdk_internal_vm_annotation_IntrinsicCandidate_signature, "Ljdk/internal/vm/annotation/IntrinsicCandidate;") \
|
template(jdk_internal_vm_annotation_IntrinsicCandidate_signature, "Ljdk/internal/vm/annotation/IntrinsicCandidate;") \
|
||||||
template(jdk_internal_vm_annotation_Stable_signature, "Ljdk/internal/vm/annotation/Stable;") \
|
template(jdk_internal_vm_annotation_Stable_signature, "Ljdk/internal/vm/annotation/Stable;") \
|
||||||
\
|
|
||||||
/* Support for JSR 292 & invokedynamic (JDK 1.7 and above) */ \
|
/* Support for JSR 292 & invokedynamic (JDK 1.7 and above) */ \
|
||||||
template(java_lang_invoke_CallSite, "java/lang/invoke/CallSite") \
|
template(java_lang_invoke_CallSite, "java/lang/invoke/CallSite") \
|
||||||
template(java_lang_invoke_ConstantCallSite, "java/lang/invoke/ConstantCallSite") \
|
template(java_lang_invoke_ConstantCallSite, "java/lang/invoke/ConstantCallSite") \
|
||||||
|
@ -203,9 +203,15 @@ JVM_IsDynamicDumpingEnabled(JNIEnv* env);
|
|||||||
JNIEXPORT jboolean JNICALL
|
JNIEXPORT jboolean JNICALL
|
||||||
JVM_IsSharingEnabled(JNIEnv* env);
|
JVM_IsSharingEnabled(JNIEnv* env);
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
JVM_IsDumpingClassList(JNIEnv* env);
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL
|
JNIEXPORT jlong JNICALL
|
||||||
JVM_GetRandomSeedForDumping();
|
JVM_GetRandomSeedForDumping();
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
JVM_LogLambdaFormInvoker(JNIEnv* env, jstring line);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* java.lang.Throwable
|
* java.lang.Throwable
|
||||||
*/
|
*/
|
||||||
|
@ -27,8 +27,9 @@
|
|||||||
#include "classfile/classLoaderDataShared.hpp"
|
#include "classfile/classLoaderDataShared.hpp"
|
||||||
#include "classfile/classListParser.hpp"
|
#include "classfile/classListParser.hpp"
|
||||||
#include "classfile/classLoaderExt.hpp"
|
#include "classfile/classLoaderExt.hpp"
|
||||||
#include "classfile/loaderConstraints.hpp"
|
|
||||||
#include "classfile/javaClasses.inline.hpp"
|
#include "classfile/javaClasses.inline.hpp"
|
||||||
|
#include "classfile/lambdaFormInvokers.hpp"
|
||||||
|
#include "classfile/loaderConstraints.hpp"
|
||||||
#include "classfile/placeholders.hpp"
|
#include "classfile/placeholders.hpp"
|
||||||
#include "classfile/symbolTable.hpp"
|
#include "classfile/symbolTable.hpp"
|
||||||
#include "classfile/stringTable.hpp"
|
#include "classfile/stringTable.hpp"
|
||||||
@ -1050,8 +1051,14 @@ void MetaspaceShared::preload_and_dump(TRAPS) {
|
|||||||
if (SharedArchiveConfigFile) {
|
if (SharedArchiveConfigFile) {
|
||||||
log_info(cds)("Reading extra data from %s ...", SharedArchiveConfigFile);
|
log_info(cds)("Reading extra data from %s ...", SharedArchiveConfigFile);
|
||||||
read_extra_data(SharedArchiveConfigFile, THREAD);
|
read_extra_data(SharedArchiveConfigFile, THREAD);
|
||||||
}
|
|
||||||
log_info(cds)("Reading extra data: done.");
|
log_info(cds)("Reading extra data: done.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LambdaFormInvokers::lambdaform_lines() != NULL) {
|
||||||
|
log_info(cds)("Regenerate MethodHandle Holder classes...");
|
||||||
|
LambdaFormInvokers::regenerate_holder_classes(THREAD);
|
||||||
|
log_info(cds)("Regenerate MethodHandle Holder classes done.");
|
||||||
|
}
|
||||||
|
|
||||||
HeapShared::init_for_dumping(THREAD);
|
HeapShared::init_for_dumping(THREAD);
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include "classfile/classLoadInfo.hpp"
|
#include "classfile/classLoadInfo.hpp"
|
||||||
#include "classfile/javaAssertions.hpp"
|
#include "classfile/javaAssertions.hpp"
|
||||||
#include "classfile/javaClasses.inline.hpp"
|
#include "classfile/javaClasses.inline.hpp"
|
||||||
|
#include "classfile/lambdaFormInvokers.hpp"
|
||||||
#include "classfile/moduleEntry.hpp"
|
#include "classfile/moduleEntry.hpp"
|
||||||
#include "classfile/modules.hpp"
|
#include "classfile/modules.hpp"
|
||||||
#include "classfile/packageEntry.hpp"
|
#include "classfile/packageEntry.hpp"
|
||||||
@ -3866,6 +3867,24 @@ JVM_ENTRY_NO_ENV(jlong, JVM_GetRandomSeedForDumping())
|
|||||||
}
|
}
|
||||||
JVM_END
|
JVM_END
|
||||||
|
|
||||||
|
JVM_ENTRY(jboolean, JVM_IsDumpingClassList(JNIEnv *env))
|
||||||
|
JVMWrapper("JVM_IsDumpingClassList");
|
||||||
|
return DumpLoadedClassList != NULL && classlist_file != NULL && classlist_file->is_open();
|
||||||
|
JVM_END
|
||||||
|
|
||||||
|
JVM_ENTRY(void, JVM_LogLambdaFormInvoker(JNIEnv *env, jstring line))
|
||||||
|
JVMWrapper("JVM_LogLambdaFormInvoker");
|
||||||
|
#if INCLUDE_CDS
|
||||||
|
assert(DumpLoadedClassList != NULL && classlist_file->is_open(), "Should be set and open");
|
||||||
|
if (line != NULL) {
|
||||||
|
ResourceMark rm(THREAD);
|
||||||
|
Handle h_line (THREAD, JNIHandles::resolve_non_null(line));
|
||||||
|
char* c_line = java_lang_String::as_utf8_string(h_line());
|
||||||
|
classlist_file->print_cr("%s %s", LambdaFormInvokers::lambda_form_invoker_tag(), c_line);
|
||||||
|
}
|
||||||
|
#endif // INCLUDE_CDS
|
||||||
|
JVM_END
|
||||||
|
|
||||||
// Returns an array of all live Thread objects (VM internal JavaThreads,
|
// Returns an array of all live Thread objects (VM internal JavaThreads,
|
||||||
// jvmti agent threads, and JNI attaching threads are skipped)
|
// jvmti agent threads, and JNI attaching threads are skipped)
|
||||||
// See CR 6404306 regarding JNI attaching threads
|
// See CR 6404306 regarding JNI attaching threads
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
package java.lang.invoke;
|
package java.lang.invoke;
|
||||||
|
|
||||||
|
import jdk.internal.misc.CDS;
|
||||||
import jdk.internal.org.objectweb.asm.ClassWriter;
|
import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||||
import sun.invoke.util.Wrapper;
|
import sun.invoke.util.Wrapper;
|
||||||
@ -32,6 +33,7 @@ import sun.invoke.util.Wrapper;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
@ -58,12 +60,18 @@ class GenerateJLIClassesHelper {
|
|||||||
shortenSignature(basicTypeSignature(type)) +
|
shortenSignature(basicTypeSignature(type)) +
|
||||||
(resolvedMember != null ? " (success)" : " (fail)"));
|
(resolvedMember != null ? " (success)" : " (fail)"));
|
||||||
}
|
}
|
||||||
|
if (CDS.isDumpingClassList()) {
|
||||||
|
CDS.traceLambdaFormInvoker(LF_RESOLVE, holder.getName(), name, shortenSignature(basicTypeSignature(type)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void traceSpeciesType(String cn, Class<?> salvage) {
|
static void traceSpeciesType(String cn, Class<?> salvage) {
|
||||||
if (TRACE_RESOLVE) {
|
if (TRACE_RESOLVE) {
|
||||||
System.out.println(SPECIES_RESOLVE + " " + cn + (salvage != null ? " (salvaged)" : " (generated)"));
|
System.out.println(SPECIES_RESOLVE + " " + cn + (salvage != null ? " (salvaged)" : " (generated)"));
|
||||||
}
|
}
|
||||||
|
if (CDS.isDumpingClassList()) {
|
||||||
|
CDS.traceSpeciesType(SPECIES_RESOLVE, cn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map from DirectMethodHandle method type name to index to LambdForms
|
// Map from DirectMethodHandle method type name to index to LambdForms
|
||||||
@ -310,13 +318,14 @@ class GenerateJLIClassesHelper {
|
|||||||
* jlink phase.
|
* jlink phase.
|
||||||
*/
|
*/
|
||||||
static Map<String, byte[]> generateHolderClasses(Stream<String> traces) {
|
static Map<String, byte[]> generateHolderClasses(Stream<String> traces) {
|
||||||
|
Objects.requireNonNull(traces);
|
||||||
HolderClassBuilder builder = new HolderClassBuilder();
|
HolderClassBuilder builder = new HolderClassBuilder();
|
||||||
traces.map(line -> line.split(" "))
|
traces.map(line -> line.split(" "))
|
||||||
.forEach(parts -> {
|
.forEach(parts -> {
|
||||||
switch (parts[0]) {
|
switch (parts[0]) {
|
||||||
case SPECIES_RESOLVE:
|
case SPECIES_RESOLVE:
|
||||||
// Allow for new types of species data classes being resolved here
|
// Allow for new types of species data classes being resolved here
|
||||||
assert parts.length == 3;
|
assert parts.length >= 2;
|
||||||
if (parts[1].startsWith(BMH_SPECIES_PREFIX)) {
|
if (parts[1].startsWith(BMH_SPECIES_PREFIX)) {
|
||||||
String species = parts[1].substring(BMH_SPECIES_PREFIX.length());
|
String species = parts[1].substring(BMH_SPECIES_PREFIX.length());
|
||||||
if (!"L".equals(species)) {
|
if (!"L".equals(species)) {
|
||||||
|
@ -25,7 +25,29 @@
|
|||||||
|
|
||||||
package jdk.internal.misc;
|
package jdk.internal.misc;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import jdk.internal.access.JavaLangInvokeAccess;
|
||||||
|
import jdk.internal.access.SharedSecrets;
|
||||||
|
|
||||||
public class CDS {
|
public class CDS {
|
||||||
|
private static final boolean isDumpingClassList;
|
||||||
|
static {
|
||||||
|
isDumpingClassList = isDumpingClassList0();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* indicator for dumping class list.
|
||||||
|
*/
|
||||||
|
public static boolean isDumpingClassList() {
|
||||||
|
return isDumpingClassList;
|
||||||
|
}
|
||||||
|
private static native boolean isDumpingClassList0();
|
||||||
|
private static native void logLambdaFormInvoker(String line);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize archived static fields in the given Class using archived
|
* Initialize archived static fields in the given Class using archived
|
||||||
* values from CDS dump time. Also initialize the classes of objects in
|
* values from CDS dump time. Also initialize the classes of objects in
|
||||||
@ -59,4 +81,110 @@ public class CDS {
|
|||||||
* Check if sharing is enabled via the UseSharedSpaces flag.
|
* Check if sharing is enabled via the UseSharedSpaces flag.
|
||||||
*/
|
*/
|
||||||
public static native boolean isSharingEnabled();
|
public static native boolean isSharingEnabled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* log lambda form invoker holder, name and method type
|
||||||
|
*/
|
||||||
|
public static void traceLambdaFormInvoker(String prefix, String holder, String name, String type) {
|
||||||
|
if (isDumpingClassList) {
|
||||||
|
logLambdaFormInvoker(prefix + " " + holder + " " + name + " " + type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* log species
|
||||||
|
*/
|
||||||
|
public static void traceSpeciesType(String prefix, String cn) {
|
||||||
|
if (isDumpingClassList) {
|
||||||
|
logLambdaFormInvoker(prefix + " " + cn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final String DIRECT_HOLDER_CLASS_NAME = "java.lang.invoke.DirectMethodHandle$Holder";
|
||||||
|
static final String DELEGATING_HOLDER_CLASS_NAME = "java.lang.invoke.DelegatingMethodHandle$Holder";
|
||||||
|
static final String BASIC_FORMS_HOLDER_CLASS_NAME = "java.lang.invoke.LambdaForm$Holder";
|
||||||
|
static final String INVOKERS_HOLDER_CLASS_NAME = "java.lang.invoke.Invokers$Holder";
|
||||||
|
|
||||||
|
private static boolean isValidHolderName(String name) {
|
||||||
|
return name.equals(DIRECT_HOLDER_CLASS_NAME) ||
|
||||||
|
name.equals(DELEGATING_HOLDER_CLASS_NAME) ||
|
||||||
|
name.equals(BASIC_FORMS_HOLDER_CLASS_NAME) ||
|
||||||
|
name.equals(INVOKERS_HOLDER_CLASS_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isBasicTypeChar(char c) {
|
||||||
|
return "LIJFDV".indexOf(c) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isValidMethodType(String type) {
|
||||||
|
String[] typeParts = type.split("_");
|
||||||
|
// check return type (second part)
|
||||||
|
if (typeParts.length != 2 || typeParts[1].length() != 1
|
||||||
|
|| !isBasicTypeChar(typeParts[1].charAt(0))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// first part
|
||||||
|
if (!isBasicTypeChar(typeParts[0].charAt(0))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 1; i < typeParts[0].length(); i++) {
|
||||||
|
char c = typeParts[0].charAt(i);
|
||||||
|
if (!isBasicTypeChar(c)) {
|
||||||
|
if (!(c >= '0' && c <= '9')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Throw exception on invalid input
|
||||||
|
private static void validateInputLines(String[] lines) {
|
||||||
|
for (String s: lines) {
|
||||||
|
// There might be a trailing '\f' for line in ExtraClassListFile, do trim first.
|
||||||
|
String line = s.trim();
|
||||||
|
if (!line.startsWith("[LF_RESOLVE]") && !line.startsWith("[SPECIES_RESOLVE]")) {
|
||||||
|
throw new IllegalArgumentException("Wrong prefix: " + line);
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] parts = line.split(" ");
|
||||||
|
boolean isLF = line.startsWith("[LF_RESOLVE]");
|
||||||
|
|
||||||
|
if (isLF) {
|
||||||
|
if (parts.length != 4) {
|
||||||
|
throw new IllegalArgumentException("Incorrect number of items in the line: " + parts.length);
|
||||||
|
}
|
||||||
|
if (!isValidHolderName(parts[1])) {
|
||||||
|
throw new IllegalArgumentException("Invalid holder class name: " + parts[1]);
|
||||||
|
}
|
||||||
|
if (!isValidMethodType(parts[3])) {
|
||||||
|
throw new IllegalArgumentException("Invalid method type: " + parts[3]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (parts.length != 2) {
|
||||||
|
throw new IllegalArgumentException("Incorrect number of items in the line: " + parts.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* called from vm to generate MethodHandle holder classes
|
||||||
|
* @return {@code Object[]} if holder classes can be generated.
|
||||||
|
* @param lines in format of LF_RESOLVE or SPECIES_RESOLVE output
|
||||||
|
*/
|
||||||
|
private static Object[] generateLambdaFormHolderClasses(String[] lines) {
|
||||||
|
Objects.requireNonNull(lines);
|
||||||
|
validateInputLines(lines);
|
||||||
|
Stream<String> lineStream = Arrays.stream(lines).map(String::trim);
|
||||||
|
Map<String, byte[]> result = SharedSecrets.getJavaLangInvokeAccess().generateHolderClasses(lineStream);
|
||||||
|
int size = result.size();
|
||||||
|
Object[] retArray = new Object[size * 2];
|
||||||
|
int index = 0;
|
||||||
|
for (Map.Entry<String, byte[]> entry : result.entrySet()) {
|
||||||
|
retArray[index++] = entry.getKey();
|
||||||
|
retArray[index++] = entry.getValue();
|
||||||
|
};
|
||||||
|
return retArray;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,3 +53,13 @@ JNIEXPORT jboolean JNICALL
|
|||||||
Java_jdk_internal_misc_CDS_isSharingEnabled(JNIEnv *env, jclass jcls) {
|
Java_jdk_internal_misc_CDS_isSharingEnabled(JNIEnv *env, jclass jcls) {
|
||||||
return JVM_IsSharingEnabled(env);
|
return JVM_IsSharingEnabled(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_jdk_internal_misc_CDS_isDumpingClassList0(JNIEnv *env, jclass jcls) {
|
||||||
|
return JVM_IsDumpingClassList(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_jdk_internal_misc_CDS_logLambdaFormInvoker(JNIEnv *env, jclass jcls, jstring line) {
|
||||||
|
JVM_LogLambdaFormInvoker(env, line);
|
||||||
|
}
|
||||||
|
@ -330,6 +330,7 @@ hotspot_appcds_dynamic = \
|
|||||||
-runtime/cds/appcds/sharedStrings \
|
-runtime/cds/appcds/sharedStrings \
|
||||||
-runtime/cds/appcds/ArchiveRelocationTest.java \
|
-runtime/cds/appcds/ArchiveRelocationTest.java \
|
||||||
-runtime/cds/appcds/DumpClassList.java \
|
-runtime/cds/appcds/DumpClassList.java \
|
||||||
|
-runtime/cds/appcds/DumpClassListWithLF.java \
|
||||||
-runtime/cds/appcds/ExtraSymbols.java \
|
-runtime/cds/appcds/ExtraSymbols.java \
|
||||||
-runtime/cds/appcds/LongClassListPath.java \
|
-runtime/cds/appcds/LongClassListPath.java \
|
||||||
-runtime/cds/appcds/LotsOfClasses.java \
|
-runtime/cds/appcds/LotsOfClasses.java \
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -25,7 +25,7 @@
|
|||||||
import jdk.test.lib.process.OutputAnalyzer;
|
import jdk.test.lib.process.OutputAnalyzer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for ClassListFormat[A,B,C...].java
|
* Base class for DumpClassListWithLF, customerLoader/ClassListFormat[A,B,C...].java
|
||||||
*/
|
*/
|
||||||
public class ClassListFormatBase {
|
public class ClassListFormatBase {
|
||||||
protected static String RUN_ONLY_TEST = null;
|
protected static String RUN_ONLY_TEST = null;
|
109
test/hotspot/jtreg/runtime/cds/appcds/DumpClassListWithLF.java
Normal file
109
test/hotspot/jtreg/runtime/cds/appcds/DumpClassListWithLF.java
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* 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 the format checking of LF_RESOLVE in classlist.
|
||||||
|
*
|
||||||
|
* @requires vm.cds
|
||||||
|
* @library /test/lib
|
||||||
|
* @compile test-classes/Hello.java
|
||||||
|
* @run driver DumpClassListWithLF
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class DumpClassListWithLF extends ClassListFormatBase {
|
||||||
|
static final String REPLACE_OK = "Replaced class java/lang/invoke/DirectMethodHandle$Holder";
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Throwable {
|
||||||
|
String appJar = JarBuilder.getOrCreateHelloJar();
|
||||||
|
//
|
||||||
|
// Note the class regeneration via jdk/internal/misc/CDS.generateLambdaFormHolderClasses(String[] lines)
|
||||||
|
// Whether the regeneration successes or fails, the dump should pass. Only the message can be checked for result.
|
||||||
|
//
|
||||||
|
// 1. With correct line format.
|
||||||
|
dumpShouldPass(
|
||||||
|
"TESTCASE 1: With correct line format",
|
||||||
|
appJar, classlist(
|
||||||
|
"Hello",
|
||||||
|
"@lambda-form-invoker [LF_RESOLVE] java.lang.invoke.DirectMethodHandle$Holder invokeStatic LL_I"),
|
||||||
|
REPLACE_OK);
|
||||||
|
|
||||||
|
// 2. The line with incorrect (less) number of items.
|
||||||
|
dumpShouldPass(
|
||||||
|
"TESTCASE 2: With incorrect (less) number of items",
|
||||||
|
appJar, classlist(
|
||||||
|
"Hello",
|
||||||
|
"@lambda-form-invoker [LF_RESOLVE] java.lang.invoke.DirectMethodHandle$Holder invokeStatic"),
|
||||||
|
"Incorrect number of items in the line: 3");
|
||||||
|
// 3. The two lines with non existed class name, since only 4 holder classes recognizable, all other names will be rejected.
|
||||||
|
dumpShouldPass(
|
||||||
|
"TESTCASE 3: With incorrect class name will be rejected",
|
||||||
|
appJar, classlist(
|
||||||
|
"Hello",
|
||||||
|
"@lambda-form-invoker [LF_RESOLVE] my.nonexist.package.MyNonExistClassName$holder invokeStatic LL_I"),
|
||||||
|
"Invalid holder class name: my.nonexist.package.MyNonExistClassName$holder" );
|
||||||
|
// 4. The two lines with arbitrary invoke names is OK. The method type will not be added.
|
||||||
|
dumpShouldPass(
|
||||||
|
"TESTCASE 4: With incorrect invoke names is OK",
|
||||||
|
appJar, classlist(
|
||||||
|
"Hello",
|
||||||
|
"@lambda-form-invoker [LF_RESOLVE] java.lang.invoke.DirectMethodHandle$Holder invokeNothing LL_I"),
|
||||||
|
REPLACE_OK);
|
||||||
|
// 5. The line with worng signature format of return type, will be rejected
|
||||||
|
dumpShouldPass(
|
||||||
|
"TESTCASE 5: With incorrect signature format of return type will be rejected",
|
||||||
|
appJar, classlist(
|
||||||
|
"Hello",
|
||||||
|
"@lambda-form-invoker [LF_RESOLVE] java.lang.invoke.DirectMethodHandle$Holder invokeStatic LL_G"),
|
||||||
|
"Invalid method type: LL_G");
|
||||||
|
// 6. The line with worng signature format of arg types, will be rejected
|
||||||
|
dumpShouldPass(
|
||||||
|
"TESTCASE 6: With incorrect signature format of arg types will be rejected",
|
||||||
|
appJar, classlist(
|
||||||
|
"Hello",
|
||||||
|
"@lambda-form-invoker [LF_RESOLVE] java.lang.invoke.DirectMethodHandle$Holder invokeStatic MGLL_I"),
|
||||||
|
"Invalid method type: MGLL_I");
|
||||||
|
// 7. The line with worng prefix will ge rejected
|
||||||
|
dumpShouldPass(
|
||||||
|
"TESTCASE 7: With incorrect LF format, the line will be rejected",
|
||||||
|
appJar, classlist(
|
||||||
|
"Hello",
|
||||||
|
"@lambda-form-invoker [LF_XYRESOLVE] java.lang.invoke.DirectMethodHandle$Holder invokeStatic LL_I"),
|
||||||
|
"Wrong prefix: [LF_XYRESOLVE]");
|
||||||
|
// 8. The line with correct species format
|
||||||
|
dumpShouldPass(
|
||||||
|
"TESTCASE 8: With correct correct species format",
|
||||||
|
appJar, classlist(
|
||||||
|
"Hello",
|
||||||
|
"@lambda-form-invoker [SPECIES_RESOLVE] java.lang.invoke.BoundMethodHandle$Species_L"),
|
||||||
|
REPLACE_OK);
|
||||||
|
// 9. The line with incorrect species length is not OK
|
||||||
|
dumpShouldPass(
|
||||||
|
"TESTCASE 9: With incorrect species length is not OK",
|
||||||
|
appJar, classlist(
|
||||||
|
"Hello",
|
||||||
|
"@lambda-form-invoker [SPECIES_RESOLVE] java.lang.invoke.BoundMethodHandle$Species_L L"),
|
||||||
|
"Incorrect number of items in the line: 3");
|
||||||
|
}
|
||||||
|
}
|
@ -28,7 +28,7 @@
|
|||||||
* @requires vm.cds
|
* @requires vm.cds
|
||||||
* @requires vm.cds.custom.loaders
|
* @requires vm.cds.custom.loaders
|
||||||
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
|
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
|
||||||
* @compile ClassListFormatBase.java ../test-classes/Hello.java test-classes/InProhibitedPkg.java
|
* @compile ../ClassListFormatBase.java ../test-classes/Hello.java test-classes/InProhibitedPkg.java
|
||||||
* @run driver ProhibitedPackageNamesTest
|
* @run driver ProhibitedPackageNamesTest
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user