8247666: Support Lambda proxy classes in static CDS archive

Reviewed-by: iklam, mchung
This commit is contained in:
Calvin Cheung 2020-10-19 18:27:50 +00:00
parent e2e11d3449
commit 74ac77e2b1
38 changed files with 1960 additions and 130 deletions

View File

@ -143,8 +143,7 @@ JVM_InternString
JVM_Interrupt
JVM_InvokeMethod
JVM_IsArrayClass
JVM_IsDynamicDumpingEnabled
JVM_IsSharingEnabled
JVM_IsCDSDumpingEnabled
JVM_IsConstructorIx
JVM_IsDumpingClassList
JVM_IsHiddenClass
@ -152,6 +151,7 @@ JVM_IsInterface
JVM_IsPrimitiveClass
JVM_IsRecord
JVM_IsSameClassPackage
JVM_IsSharingEnabled
JVM_IsSupportedJNIVersion
JVM_IsThreadAlive
JVM_IsVMGeneratedMethodIx

View File

@ -32,10 +32,14 @@
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "interpreter/bytecode.hpp"
#include "interpreter/bytecodeStream.hpp"
#include "interpreter/linkResolver.hpp"
#include "logging/log.hpp"
#include "logging/logTag.hpp"
#include "memory/metaspaceShared.hpp"
#include "memory/resourceArea.hpp"
#include "oops/constantPool.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/java.hpp"
#include "runtime/javaCalls.hpp"
@ -65,6 +69,7 @@ ClassListParser::ClassListParser(const char* file) {
}
_line_no = 0;
_interfaces = new (ResourceObj::C_HEAP, mtClass) GrowableArray<int>(10, mtClass);
_indy_items = new (ResourceObj::C_HEAP, mtClass) GrowableArray<const char*>(9, mtClass);
}
ClassListParser::~ClassListParser() {
@ -127,6 +132,11 @@ bool ClassListParser::parse_one_line() {
_interfaces->clear();
_source = NULL;
_interfaces_specified = false;
_indy_items->clear();
if (_line[0] == '@') {
return parse_at_tags();
}
if ((_token = strchr(_line, ' ')) == NULL) {
// No optional arguments are specified.
@ -139,14 +149,14 @@ bool ClassListParser::parse_one_line() {
while (*_token) {
skip_whitespaces();
if (parse_int_option("id:", &_id)) {
if (parse_uint_option("id:", &_id)) {
continue;
} else if (parse_int_option("super:", &_super)) {
} else if (parse_uint_option("super:", &_super)) {
check_already_loaded("Super class", _super);
continue;
} else if (skip_token("interfaces:")) {
int i;
while (try_parse_int(&i)) {
while (try_parse_uint(&i)) {
check_already_loaded("Interface", i);
_interfaces->append(i);
}
@ -175,6 +185,41 @@ bool ClassListParser::parse_one_line() {
return true;
}
void ClassListParser::split_tokens_by_whitespace() {
int start = 0;
int end;
bool done = false;
while (!done) {
while (_line[start] == ' ' || _line[start] == '\t') start++;
end = start;
while (_line[end] && _line[end] != ' ' && _line[end] != '\t') end++;
if (_line[end] == '\0') {
done = true;
} else {
_line[end] = '\0';
}
_indy_items->append(_line + start);
start = ++end;
}
}
bool ClassListParser::parse_at_tags() {
assert(_line[0] == '@', "must be");
split_tokens_by_whitespace();
if (strcmp(_indy_items->at(0), LAMBDA_PROXY_TAG) == 0) {
if (_indy_items->length() < 3) {
error("Line with @ tag has too few items \"%s\" line #%d", _line, _line_no);
return false;
}
// set the class name
_class_name = _indy_items->at(1);
return true;
} else {
error("Invalid @ tag at the beginning of line \"%s\" line #%d", _line, _line_no);
return false;
}
}
void ClassListParser::skip_whitespaces() {
while (*_token == ' ' || *_token == '\t') {
_token ++;
@ -191,15 +236,19 @@ void ClassListParser::parse_int(int* value) {
skip_whitespaces();
if (sscanf(_token, "%i", value) == 1) {
skip_non_whitespaces();
if (*value < 0) {
error("Error: negative integers not allowed (%d)", *value);
}
} else {
error("Error: expected integer");
}
}
bool ClassListParser::try_parse_int(int* value) {
void ClassListParser::parse_uint(int* value) {
parse_int(value);
if (*value < 0) {
error("Error: negative integers not allowed (%d)", *value);
}
}
bool ClassListParser::try_parse_uint(int* value) {
skip_whitespaces();
if (sscanf(_token, "%i", value) == 1) {
skip_non_whitespaces();
@ -230,6 +279,18 @@ bool ClassListParser::parse_int_option(const char* option_name, int* value) {
return false;
}
bool ClassListParser::parse_uint_option(const char* option_name, int* value) {
if (skip_token(option_name)) {
if (*value != _unspecified) {
error("%s specified twice", option_name);
} else {
parse_uint(value);
return true;
}
}
return false;
}
void ClassListParser::print_specified_interfaces() {
const int n = _interfaces->length();
jio_fprintf(defaultStream::error_stream(), "Currently specified interfaces[%d] = {\n", n);
@ -336,9 +397,122 @@ InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS
return k;
}
void ClassListParser::populate_cds_indy_info(const constantPoolHandle &pool, int cp_index, CDSIndyInfo* cii, TRAPS) {
// Caller needs to allocate ResourceMark.
int type_index = pool->bootstrap_name_and_type_ref_index_at(cp_index);
int name_index = pool->name_ref_index_at(type_index);
cii->add_item(pool->symbol_at(name_index)->as_C_string());
int sig_index = pool->signature_ref_index_at(type_index);
cii->add_item(pool->symbol_at(sig_index)->as_C_string());
int argc = pool->bootstrap_argument_count_at(cp_index);
if (argc > 0) {
for (int arg_i = 0; arg_i < argc; arg_i++) {
int arg = pool->bootstrap_argument_index_at(cp_index, arg_i);
jbyte tag = pool->tag_at(arg).value();
if (tag == JVM_CONSTANT_MethodType) {
cii->add_item(pool->method_type_signature_at(arg)->as_C_string());
} else if (tag == JVM_CONSTANT_MethodHandle) {
cii->add_ref_kind(pool->method_handle_ref_kind_at(arg));
int callee_index = pool->method_handle_klass_index_at(arg);
Klass* callee = pool->klass_at(callee_index, THREAD);
if (callee != NULL) {
cii->add_item(callee->name()->as_C_string());
}
cii->add_item(pool->method_handle_name_ref_at(arg)->as_C_string());
cii->add_item(pool->method_handle_signature_ref_at(arg)->as_C_string());
} else {
ShouldNotReachHere();
}
}
}
}
bool ClassListParser::is_matching_cp_entry(constantPoolHandle &pool, int cp_index, TRAPS) {
ResourceMark rm(THREAD);
CDSIndyInfo cii;
populate_cds_indy_info(pool, cp_index, &cii, THREAD);
GrowableArray<const char*>* items = cii.items();
int indy_info_offset = 2;
if (_indy_items->length() - indy_info_offset != items->length()) {
return false;
}
for (int i = 0; i < items->length(); i++) {
if (strcmp(_indy_items->at(i + indy_info_offset), items->at(i)) != 0) {
return false;
}
}
return true;
}
void ClassListParser::resolve_indy(Symbol* class_name_symbol, TRAPS) {
Handle class_loader(THREAD, SystemDictionary::java_system_loader());
Handle protection_domain;
Klass* klass = SystemDictionary::resolve_or_fail(class_name_symbol, class_loader, protection_domain, true, THREAD); // FIXME should really be just a lookup
if (klass != NULL && klass->is_instance_klass()) {
InstanceKlass* ik = InstanceKlass::cast(klass);
MetaspaceShared::try_link_class(ik, THREAD);
assert(!HAS_PENDING_EXCEPTION, "unexpected exception");
ConstantPool* cp = ik->constants();
ConstantPoolCache* cpcache = cp->cache();
bool found = false;
for (int cpcindex = 0; cpcindex < cpcache->length(); cpcindex ++) {
int indy_index = ConstantPool::encode_invokedynamic_index(cpcindex);
ConstantPoolCacheEntry* cpce = cpcache->entry_at(cpcindex);
int pool_index = cpce->constant_pool_index();
constantPoolHandle pool(THREAD, cp);
if (pool->tag_at(pool_index).is_invoke_dynamic()) {
BootstrapInfo bootstrap_specifier(pool, pool_index, indy_index);
Handle bsm = bootstrap_specifier.resolve_bsm(THREAD);
if (!SystemDictionaryShared::is_supported_invokedynamic(&bootstrap_specifier)) {
tty->print_cr("is_supported_invokedynamic check failed for cp_index %d", pool_index);
continue;
}
if (is_matching_cp_entry(pool, pool_index, THREAD)) {
found = true;
CallInfo info;
bool is_done = bootstrap_specifier.resolve_previously_linked_invokedynamic(info, THREAD);
if (!is_done) {
// resolve it
Handle recv;
LinkResolver::resolve_invoke(info, recv, pool, indy_index, Bytecodes::_invokedynamic, THREAD);
break;
}
cpce->set_dynamic_call(pool, info);
if (HAS_PENDING_EXCEPTION) {
ResourceMark rm(THREAD);
tty->print("resolve_indy for class %s has", class_name_symbol->as_C_string());
oop message = java_lang_Throwable::message(PENDING_EXCEPTION);
if (message != NULL) {
char* ex_msg = java_lang_String::as_utf8_string(message);
tty->print_cr(" exception pending '%s %s'",
PENDING_EXCEPTION->klass()->external_name(), ex_msg);
} else {
tty->print_cr(" exception pending %s ",
PENDING_EXCEPTION->klass()->external_name());
}
exit(1);
}
}
}
}
if (!found) {
ResourceMark rm(THREAD);
log_warning(cds)("No invoke dynamic constant pool entry can be found for class %s. The classlist is probably out-of-date.",
class_name_symbol->as_C_string());
}
}
}
Klass* ClassListParser::load_current_class(TRAPS) {
TempNewSymbol class_name_symbol = SymbolTable::new_symbol(_class_name);
if (_indy_items->length() > 0) {
resolve_indy(class_name_symbol, CHECK_NULL);
return NULL;
}
Klass* klass = NULL;
if (!is_loading_from_source()) {
// Load classes for the boot/platform/app loaders only.

View File

@ -30,11 +30,43 @@
#include "utilities/growableArray.hpp"
#include "utilities/hashtable.inline.hpp"
#define LAMBDA_PROXY_TAG "@lambda-proxy:"
class ID2KlassTable : public KVHashtable<int, InstanceKlass*, mtInternal> {
public:
ID2KlassTable() : KVHashtable<int, InstanceKlass*, mtInternal>(1987) {}
};
class CDSIndyInfo {
GrowableArray<const char*>* _items;
public:
CDSIndyInfo() : _items(NULL) {}
void add_item(const char* item) {
if (_items == NULL) {
_items = new GrowableArray<const char*>(9);
}
assert(_items != NULL, "sanity");
_items->append(item);
}
void add_ref_kind(int ref_kind) {
switch (ref_kind) {
case JVM_REF_getField : _items->append("REF_getField"); break;
case JVM_REF_getStatic : _items->append("REF_getStatic"); break;
case JVM_REF_putField : _items->append("REF_putField"); break;
case JVM_REF_putStatic : _items->append("REF_putStatic"); break;
case JVM_REF_invokeVirtual : _items->append("REF_invokeVirtual"); break;
case JVM_REF_invokeStatic : _items->append("REF_invokeStatic"); break;
case JVM_REF_invokeSpecial : _items->append("REF_invokeSpecial"); break;
case JVM_REF_newInvokeSpecial : _items->append("REF_newInvokeSpecial"); break;
case JVM_REF_invokeInterface : _items->append("REF_invokeInterface"); break;
default : ShouldNotReachHere();
}
}
GrowableArray<const char*>* items() {
return _items;
}
};
class ClassListParser : public StackObj {
enum {
_unspecified = -999,
@ -61,6 +93,7 @@ class ClassListParser : public StackObj {
int _line_len; // Original length of the input line.
int _line_no; // Line number for current line being parsed
const char* _class_name;
GrowableArray<const char*>* _indy_items; // items related to invoke dynamic for archiving lambda proxy classes
int _id;
int _super;
GrowableArray<int>* _interfaces;
@ -68,6 +101,7 @@ class ClassListParser : public StackObj {
const char* _source;
bool parse_int_option(const char* option_name, int* value);
bool parse_uint_option(const char* option_name, int* value);
InstanceKlass* load_class_from_source(Symbol* class_name, TRAPS);
ID2KlassTable *table() {
return &_id2klass_table;
@ -75,6 +109,9 @@ class ClassListParser : public StackObj {
InstanceKlass* lookup_class_by_id(int id);
void print_specified_interfaces();
void print_actual_interfaces(InstanceKlass *ik);
bool is_matching_cp_entry(constantPoolHandle &pool, int cp_index, TRAPS);
void resolve_indy(Symbol* class_name_symbol, TRAPS);
public:
ClassListParser(const char* file);
~ClassListParser();
@ -83,10 +120,13 @@ public:
return _instance;
}
bool parse_one_line();
void split_tokens_by_whitespace();
bool parse_at_tags();
char* _token;
void error(const char* msg, ...);
void parse_int(int* value);
bool try_parse_int(int* value);
void parse_uint(int* value);
bool try_parse_uint(int* value);
bool skip_token(const char* option_name);
void skip_whitespaces();
void skip_non_whitespaces();
@ -126,5 +166,7 @@ public:
// (in this->load_current_class()).
InstanceKlass* lookup_super_for_current_class(Symbol* super_name);
InstanceKlass* lookup_interface_for_current_class(Symbol* interface_name);
static void populate_cds_indy_info(const constantPoolHandle &pool, int cp_index, CDSIndyInfo* cii, TRAPS);
};
#endif // SHARE_CLASSFILE_CLASSLISTPARSER_HPP

View File

@ -0,0 +1,83 @@
/*
* 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_CLASSFILE_CLASSLISTWRITER_HPP
#define SHARE_CLASSFILE_CLASSLISTWRITER_HPP
#include "runtime/arguments.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/thread.hpp"
#include "utilities/ostream.hpp"
class ClassListWriter {
friend const char* make_log_name(const char* log_name, const char* force_directory);
static fileStream* _classlist_file;
MutexLocker _locker;
public:
#if INCLUDE_CDS
ClassListWriter() : _locker(Thread::current(), ClassListFile_lock, Mutex::_no_safepoint_check_flag) {}
#else
ClassListWriter() : _locker(Thread::current(), NULL, Mutex::_no_safepoint_check_flag) {}
#endif
outputStream* stream() {
return _classlist_file;
}
static bool is_enabled() {
#if INCLUDE_CDS
return _classlist_file != NULL && _classlist_file->is_open();
#else
return false;
#endif
}
static void init() {
#if INCLUDE_CDS
// For -XX:DumpLoadedClassList=<file> option
if (DumpLoadedClassList != NULL) {
const char* list_name = make_log_name(DumpLoadedClassList, NULL);
_classlist_file = new(ResourceObj::C_HEAP, mtInternal)
fileStream(list_name);
_classlist_file->print_cr("# NOTE: Do not modify this file.");
_classlist_file->print_cr("#");
_classlist_file->print_cr("# This file is generated via the -XX:DumpLoadedClassList=<class_list_file> option");
_classlist_file->print_cr("# and is used at CDS archive dump time (see -Xshare:dump).");
_classlist_file->print_cr("#");
FREE_C_HEAP_ARRAY(char, list_name);
}
#endif
}
static void delete_classlist() {
#if INCLUDE_CDS
if (_classlist_file != NULL) {
delete _classlist_file;
}
#endif
}
};
#endif // SHARE_CLASSFILE_CLASSLISTWRITER_HPP

View File

@ -1353,8 +1353,10 @@ InstanceKlass* SystemDictionary::load_shared_lambda_proxy_class(InstanceKlass* i
InstanceKlass* loaded_ik = load_shared_class(ik, class_loader, protection_domain, NULL, pkg_entry, CHECK_NULL);
assert(shared_nest_host->is_same_class_package(ik),
"lambda proxy class and its nest host must be in the same package");
if (loaded_ik != NULL) {
assert(shared_nest_host->is_same_class_package(ik),
"lambda proxy class and its nest host must be in the same package");
}
return loaded_ik;
}

View File

@ -31,11 +31,13 @@
#include "classfile/classLoaderExt.hpp"
#include "classfile/dictionary.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "classfile/verificationType.hpp"
#include "classfile/vmSymbols.hpp"
#include "interpreter/bootstrapInfo.hpp"
#include "jfr/jfrEvents.hpp"
#include "logging/log.hpp"
#include "memory/allocation.hpp"
@ -98,6 +100,7 @@ public:
};
InstanceKlass* _klass;
InstanceKlass* _nest_host;
bool _failed_verification;
bool _is_archived_lambda_proxy;
int _id;
@ -109,6 +112,7 @@ public:
DumpTimeSharedClassInfo() {
_klass = NULL;
_nest_host = NULL;
_failed_verification = false;
_is_archived_lambda_proxy = false;
_id = -1;
@ -146,6 +150,7 @@ public:
void metaspace_pointers_do(MetaspaceClosure* it) {
it->push(&_klass);
it->push(&_nest_host);
if (_verifier_constraints != NULL) {
for (int i = 0; i < _verifier_constraints->length(); i++) {
DTVerifierConstraint* cons = _verifier_constraints->adr_at(i);
@ -177,6 +182,14 @@ public:
bool failed_verification() {
return _failed_verification;
}
void set_nest_host(InstanceKlass* nest_host) {
_nest_host = nest_host;
}
InstanceKlass* nest_host() {
return _nest_host;
}
};
inline unsigned DumpTimeSharedClassTable_hash(InstanceKlass* const& k) {
@ -257,7 +270,9 @@ public:
class LambdaProxyClassKey {
template <typename T> static void original_to_target(T& field) {
if (field != NULL) {
field = DynamicArchive::original_to_target(field);
if (DynamicDumpSharedSpaces) {
field = DynamicArchive::original_to_target(field);
}
ArchivePtrMarker::mark_pointer(&field);
}
}
@ -283,6 +298,15 @@ public:
_member_method(member_method),
_instantiated_method_type(instantiated_method_type) {}
void metaspace_pointers_do(MetaspaceClosure* it) {
it->push(&_caller_ik);
it->push(&_invoked_name);
it->push(&_invoked_type);
it->push(&_method_type);
it->push(&_member_method);
it->push(&_instantiated_method_type);
}
void original_to_target() {
original_to_target(_caller_ik);
original_to_target(_instantiated_method_type);
@ -309,12 +333,20 @@ public:
SystemDictionaryShared::hash_for_shared_dictionary(_instantiated_method_type);
}
static unsigned int dumptime_hash(Symbol* sym) {
if (sym == NULL) {
// _invoked_name maybe NULL
return 0;
}
return java_lang_String::hash_code((const jbyte*)sym->bytes(), sym->utf8_length());
}
unsigned int dumptime_hash() const {
return primitive_hash<InstanceKlass*>(_caller_ik) +
primitive_hash<Symbol*>(_invoked_name) +
primitive_hash<Symbol*>(_invoked_type) +
primitive_hash<Symbol*>(_method_type) +
primitive_hash<Symbol*>(_instantiated_method_type);
return dumptime_hash(_caller_ik->name()) +
dumptime_hash(_invoked_name) +
dumptime_hash(_invoked_type) +
dumptime_hash(_method_type) +
dumptime_hash(_instantiated_method_type);
}
static inline unsigned int DUMPTIME_HASH(LambdaProxyClassKey const& key) {
@ -339,14 +371,20 @@ public:
assert(_proxy_klasses != NULL, "sanity");
_proxy_klasses->append(proxy_klass);
}
void metaspace_pointers_do(MetaspaceClosure* it) {
for (int i=0; i<_proxy_klasses->length(); i++) {
it->push(_proxy_klasses->adr_at(i));
}
}
};
class RunTimeLambdaProxyClassInfo {
LambdaProxyClassKey _key;
InstanceKlass* _proxy_klass_head;
public:
RunTimeLambdaProxyClassInfo(LambdaProxyClassKey key, InstanceKlass* proxy_klass) :
_key(key), _proxy_klass_head(proxy_klass) {}
RunTimeLambdaProxyClassInfo(LambdaProxyClassKey key, InstanceKlass* proxy_klass_head) :
_key(key), _proxy_klass_head(proxy_klass_head) {}
InstanceKlass* proxy_klass_head() const { return _proxy_klass_head; }
@ -358,13 +396,18 @@ public:
void init(LambdaProxyClassKey& key, DumpTimeLambdaProxyClassInfo& info) {
_key = key;
_key.original_to_target();
_proxy_klass_head = DynamicArchive::original_to_target(info._proxy_klasses->at(0));
_proxy_klass_head = DynamicDumpSharedSpaces ?
DynamicArchive::original_to_target(info._proxy_klasses->at(0)) :
info._proxy_klasses->at(0);
ArchivePtrMarker::mark_pointer(&_proxy_klass_head);
}
unsigned int hash() const {
return _key.hash();
}
LambdaProxyClassKey key() const {
return _key;
}
};
class LambdaProxyClassDictionary : public OffsetCompactHashtable<
@ -374,6 +417,8 @@ class LambdaProxyClassDictionary : public OffsetCompactHashtable<
LambdaProxyClassDictionary _lambda_proxy_class_dictionary;
LambdaProxyClassDictionary _dynamic_lambda_proxy_class_dictionary;
class DumpTimeLambdaProxyClassDictionary
: public ResourceHashtable<LambdaProxyClassKey,
DumpTimeLambdaProxyClassInfo,
@ -585,15 +630,15 @@ public:
ld_constraints[i]._loader_type2 = info._loader_constraints->at(i)._loader_type2;
}
}
if (DynamicDumpSharedSpaces) {
if (_klass->is_hidden()) {
Thread* THREAD = Thread::current();
InstanceKlass* n_h = _klass->nest_host(THREAD);
if (_klass->is_hidden()) {
InstanceKlass* n_h = info.nest_host();
if (DynamicDumpSharedSpaces) {
n_h = DynamicArchive::original_to_target(n_h);
set_nest_host(n_h);
}
_klass = DynamicArchive::original_to_target(info._klass);
set_nest_host(n_h);
}
_klass = DynamicDumpSharedSpaces ? DynamicArchive::original_to_target(info._klass) : info._klass;
ArchivePtrMarker::mark_pointer(&_klass);
}
@ -1389,7 +1434,7 @@ void SystemDictionaryShared::validate_before_archiving(InstanceKlass* k) {
class ExcludeDumpTimeSharedClasses : StackObj {
public:
bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
if (SystemDictionaryShared::should_be_excluded(k)) {
if (SystemDictionaryShared::should_be_excluded(k) || info.is_excluded()) {
info.set_excluded();
}
return true; // keep on iterating
@ -1449,10 +1494,26 @@ public:
}
};
class IterateDumpTimeLambdaProxyClassDictionary : StackObj {
MetaspaceClosure *_it;
public:
IterateDumpTimeLambdaProxyClassDictionary(MetaspaceClosure* it) : _it(it) {}
bool do_entry(LambdaProxyClassKey& key, DumpTimeLambdaProxyClassInfo& info) {
info.metaspace_pointers_do(_it);
key.metaspace_pointers_do(_it);
return true;
}
};
void SystemDictionaryShared::dumptime_classes_do(class MetaspaceClosure* it) {
assert_locked_or_safepoint(DumpTimeTable_lock);
IterateDumpTimeSharedClassTable iter(it);
_dumptime_table->iterate(&iter);
if (_dumptime_lambda_proxy_class_dictionary != NULL) {
IterateDumpTimeLambdaProxyClassDictionary iter_lambda(it);
_dumptime_lambda_proxy_class_dictionary->iterate(&iter_lambda);
}
}
bool SystemDictionaryShared::add_verification_constraint(InstanceKlass* k, Symbol* name,
@ -1523,7 +1584,8 @@ void SystemDictionaryShared::add_lambda_proxy_class(InstanceKlass* caller_ik,
Symbol* invoked_type,
Symbol* method_type,
Method* member_method,
Symbol* instantiated_method_type) {
Symbol* instantiated_method_type,
TRAPS) {
assert(caller_ik->class_loader() == lambda_ik->class_loader(), "mismatched class loader");
assert(caller_ik->class_loader_data() == lambda_ik->class_loader_data(), "mismatched class loader data");
@ -1533,12 +1595,14 @@ void SystemDictionaryShared::add_lambda_proxy_class(InstanceKlass* caller_ik,
lambda_ik->assign_class_loader_type();
lambda_ik->set_shared_classpath_index(caller_ik->shared_classpath_index());
InstanceKlass* nest_host = caller_ik->nest_host(THREAD);
DumpTimeSharedClassInfo* info = _dumptime_table->get(lambda_ik);
if (info != NULL && !lambda_ik->is_non_strong_hidden() && is_builtin(lambda_ik) && is_builtin(caller_ik)) {
// Set _is_archived_lambda_proxy in DumpTimeSharedClassInfo so that the lambda_ik
// won't be excluded during dumping of shared archive. See ExcludeDumpTimeSharedClasses.
info->_is_archived_lambda_proxy = true;
info->set_nest_host(nest_host);
LambdaProxyClassKey key(caller_ik,
invoked_name,
@ -1560,6 +1624,10 @@ InstanceKlass* SystemDictionaryShared::get_shared_lambda_proxy_class(InstanceKla
LambdaProxyClassKey key(caller_ik, invoked_name, invoked_type,
method_type, member_method, instantiated_method_type);
const RunTimeLambdaProxyClassInfo* info = _lambda_proxy_class_dictionary.lookup(&key, key.hash(), 0);
if (info == NULL) {
// Try lookup from the dynamic lambda proxy class dictionary.
info = _dynamic_lambda_proxy_class_dictionary.lookup(&key, key.hash(), 0);
}
InstanceKlass* proxy_klass = NULL;
if (info != NULL) {
InstanceKlass* curr_klass = info->proxy_klass_head();
@ -1577,7 +1645,7 @@ InstanceKlass* SystemDictionaryShared::get_shared_lambda_proxy_class(InstanceKla
proxy_klass->clear_lambda_proxy_is_available();
if (log_is_enabled(Debug, cds)) {
ResourceMark rm;
log_debug(cds)("Loaded lambda proxy: %s", proxy_klass->external_name());
log_debug(cds)("Loaded lambda proxy: %s ", proxy_klass->external_name());
}
} else {
if (log_is_enabled(Debug, cds)) {
@ -1612,6 +1680,10 @@ InstanceKlass* SystemDictionaryShared::prepare_shared_lambda_proxy_class(Instanc
InstanceKlass* loaded_lambda =
SystemDictionary::load_shared_lambda_proxy_class(lambda_ik, class_loader, protection_domain, pkg_entry, CHECK_NULL);
if (loaded_lambda == NULL) {
return NULL;
}
// Ensures the nest host is the same as the lambda proxy's
// nest host recorded at dump time.
InstanceKlass* nest_host = caller_ik->nest_host(THREAD);
@ -1846,6 +1918,49 @@ bool SystemDictionaryShared::check_linking_constraints(InstanceKlass* klass, TRA
return false;
}
bool SystemDictionaryShared::is_supported_invokedynamic(BootstrapInfo* bsi) {
if (bsi->arg_values() == NULL || !bsi->arg_values()->is_objArray()) {
DEBUG_ONLY(
tty->print_cr("bsi check failed");
tty->print_cr(" bsi->arg_values().not_null() %d", bsi->arg_values().not_null());
if (bsi->arg_values().not_null()) {
tty->print_cr(" bsi->arg_values()->is_objArray() %d", bsi->arg_values()->is_objArray());
bsi->print();
}
)
return false;
}
Handle bsm = bsi->bsm();
if (bsm.is_null() || !java_lang_invoke_DirectMethodHandle::is_instance(bsm())) {
DEBUG_ONLY(
tty->print_cr("bsm check failed");
tty->print_cr(" bsm.is_null() %d", bsm.is_null());
tty->print_cr(" java_lang_invoke_DirectMethodHandle::is_instance(bsm()) %d",
java_lang_invoke_DirectMethodHandle::is_instance(bsm()));
)
return false;
}
oop mn = java_lang_invoke_DirectMethodHandle::member(bsm());
Method* method = java_lang_invoke_MemberName::vmtarget(mn);
if (method->klass_name()->equals("java/lang/invoke/LambdaMetafactory") &&
method->name()->equals("metafactory") &&
method->signature()->equals("(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;")) {
return true;
} else {
DEBUG_ONLY(
ResourceMark rm;
tty->print_cr("method check failed");
tty->print_cr(" klass_name() %s", method->klass_name()->as_C_string());
tty->print_cr(" name() %s", method->name()->as_C_string());
tty->print_cr(" signature() %s", method->signature()->as_C_string());
)
}
return false;
}
class EstimateSizeForArchive : StackObj {
size_t _shared_class_info_size;
int _num_builtin_klasses;
@ -1894,9 +2009,15 @@ public:
CopyLambdaProxyClassInfoToArchive(CompactHashtableWriter* writer)
: _writer(writer) {}
bool do_entry(LambdaProxyClassKey& key, DumpTimeLambdaProxyClassInfo& info) {
if (SystemDictionaryShared::is_excluded_class(info._proxy_klasses->at(0))) {
return true;
}
// In static dump, info._proxy_klasses->at(0) is already relocated to point to the archived class
// (not the original class).
//
// The following check has been moved to SystemDictionaryShared::check_excluded_classes(), which
// happens before the classes are copied.
//
// if (SystemDictionaryShared::is_excluded_class(info._proxy_klasses->at(0))) {
// return true;
//}
ResourceMark rm;
log_info(cds,dynamic)("Archiving hidden %s", info._proxy_klasses->at(0)->external_name());
size_t byte_size = sizeof(RunTimeLambdaProxyClassInfo);
@ -1904,7 +2025,9 @@ public:
(RunTimeLambdaProxyClassInfo*)MetaspaceShared::read_only_space_alloc(byte_size);
runtime_info->init(key, info);
unsigned int hash = runtime_info->hash(); // Fields in runtime_info->_key already point to target space.
u4 delta = MetaspaceShared::object_delta_u4(DynamicArchive::buffer_to_target(runtime_info));
u4 delta = DynamicDumpSharedSpaces ?
MetaspaceShared::object_delta_u4((void*)DynamicArchive::buffer_to_target(runtime_info)) :
MetaspaceShared::object_delta_u4((void*)runtime_info);
_writer->add(hash, delta);
return true;
}
@ -1914,16 +2037,13 @@ class AdjustLambdaProxyClassInfo : StackObj {
public:
AdjustLambdaProxyClassInfo() {}
bool do_entry(LambdaProxyClassKey& key, DumpTimeLambdaProxyClassInfo& info) {
if (SystemDictionaryShared::is_excluded_class(info._proxy_klasses->at(0))) {
return true;
}
int len = info._proxy_klasses->length();
if (len > 1) {
for (int i = 0; i < len-1; i++) {
InstanceKlass* ok0 = info._proxy_klasses->at(i+0); // this is original klass
InstanceKlass* ok1 = info._proxy_klasses->at(i+1); // this is original klass
InstanceKlass* bk0 = DynamicArchive::original_to_buffer(ok0);
InstanceKlass* bk1 = DynamicArchive::original_to_buffer(ok1);
InstanceKlass* bk0 = DynamicDumpSharedSpaces ? DynamicArchive::original_to_buffer(ok0) : ok0;
InstanceKlass* bk1 = DynamicDumpSharedSpaces ? DynamicArchive::original_to_buffer(ok1) : ok1;
assert(bk0->next_link() == 0, "must be called after Klass::remove_unshareable_info()");
assert(bk1->next_link() == 0, "must be called after Klass::remove_unshareable_info()");
bk0->set_next_link(bk1);
@ -1931,7 +2051,11 @@ public:
ArchivePtrMarker::mark_pointer(bk0->next_link_addr());
}
}
DynamicArchive::original_to_buffer(info._proxy_klasses->at(0))->set_lambda_proxy_is_available();
if (DynamicDumpSharedSpaces) {
DynamicArchive::original_to_buffer(info._proxy_klasses->at(0))->set_lambda_proxy_is_available();
} else {
info._proxy_klasses->at(0)->set_lambda_proxy_is_available();
}
return true;
}
};
@ -2022,13 +2146,21 @@ void SystemDictionaryShared::adjust_lambda_proxy_class_dictionary() {
void SystemDictionaryShared::serialize_dictionary_headers(SerializeClosure* soc,
bool is_static_archive) {
FileMapInfo *dynamic_mapinfo = FileMapInfo::dynamic_info();
if (is_static_archive) {
_builtin_dictionary.serialize_header(soc);
_unregistered_dictionary.serialize_header(soc);
if (dynamic_mapinfo == NULL || DynamicDumpSharedSpaces || (dynamic_mapinfo != NULL && UseSharedSpaces)) {
_lambda_proxy_class_dictionary.serialize_header(soc);
}
} else {
_dynamic_builtin_dictionary.serialize_header(soc);
_dynamic_unregistered_dictionary.serialize_header(soc);
_lambda_proxy_class_dictionary.serialize_header(soc);
if (DynamicDumpSharedSpaces) {
_lambda_proxy_class_dictionary.serialize_header(soc);
} else {
_dynamic_lambda_proxy_class_dictionary.serialize_header(soc);
}
}
}
@ -2106,20 +2238,28 @@ public:
}
};
void SystemDictionaryShared::print_on(const char* prefix,
RunTimeSharedDictionary* builtin_dictionary,
RunTimeSharedDictionary* unregistered_dictionary,
LambdaProxyClassDictionary* lambda_dictionary,
outputStream* st) {
st->print_cr("%sShared Dictionary", prefix);
SharedDictionaryPrinter p(st);
builtin_dictionary->iterate(&p);
unregistered_dictionary->iterate(&p);
if (!lambda_dictionary->empty()) {
st->print_cr("%sShared Lambda Dictionary", prefix);
SharedLambdaDictionaryPrinter ldp(st);
lambda_dictionary->iterate(&ldp);
}
}
void SystemDictionaryShared::print_on(outputStream* st) {
if (UseSharedSpaces) {
st->print_cr("Shared Dictionary");
SharedDictionaryPrinter p(st);
_builtin_dictionary.iterate(&p);
_unregistered_dictionary.iterate(&p);
print_on("", &_builtin_dictionary, &_unregistered_dictionary, &_lambda_proxy_class_dictionary, st);
if (DynamicArchive::is_mapped()) {
_dynamic_builtin_dictionary.iterate(&p);
_unregistered_dictionary.iterate(&p);
if (!_lambda_proxy_class_dictionary.empty()) {
st->print_cr("Shared Lambda Dictionary");
SharedLambdaDictionaryPrinter ldp(st);
_lambda_proxy_class_dictionary.iterate(&ldp);
}
print_on("", &_dynamic_builtin_dictionary, &_dynamic_unregistered_dictionary,
&_dynamic_lambda_proxy_class_dictionary, st);
}
}
}
@ -2128,10 +2268,11 @@ void SystemDictionaryShared::print_table_statistics(outputStream* st) {
if (UseSharedSpaces) {
_builtin_dictionary.print_table_statistics(st, "Builtin Shared Dictionary");
_unregistered_dictionary.print_table_statistics(st, "Unregistered Shared Dictionary");
_lambda_proxy_class_dictionary.print_table_statistics(st, "Lambda Shared Dictionary");
if (DynamicArchive::is_mapped()) {
_dynamic_builtin_dictionary.print_table_statistics(st, "Dynamic Builtin Shared Dictionary");
_dynamic_unregistered_dictionary.print_table_statistics(st, "Unregistered Shared Dictionary");
_lambda_proxy_class_dictionary.print_table_statistics(st, "Lambda Shared Dictionary");
_dynamic_lambda_proxy_class_dictionary.print_table_statistics(st, "Dynamic Lambda Shared Dictionary");
}
}
}
@ -2150,6 +2291,7 @@ bool SystemDictionaryShared::empty_dumptime_table() {
#if INCLUDE_CDS_JAVA_HEAP
class ArchivedMirrorPatcher {
protected:
static void update(Klass* k) {
if (k->has_raw_archived_mirror()) {
oop m = HeapShared::materialize_archived_object(k->archived_java_mirror_raw_narrow());
@ -2174,11 +2316,28 @@ public:
}
};
class ArchivedLambdaMirrorPatcher : public ArchivedMirrorPatcher {
public:
void do_value(const RunTimeLambdaProxyClassInfo* info) {
InstanceKlass* ik = info->proxy_klass_head();
while (ik != NULL) {
update(ik);
Klass* k = ik->next_link();
ik = (k != NULL) ? InstanceKlass::cast(k) : NULL;
}
}
};
void SystemDictionaryShared::update_archived_mirror_native_pointers_for(RunTimeSharedDictionary* dict) {
ArchivedMirrorPatcher patcher;
dict->iterate(&patcher);
}
void SystemDictionaryShared::update_archived_mirror_native_pointers_for(LambdaProxyClassDictionary* dict) {
ArchivedLambdaMirrorPatcher patcher;
dict->iterate(&patcher);
}
void SystemDictionaryShared::update_archived_mirror_native_pointers() {
if (!HeapShared::open_archive_heap_region_mapped()) {
return;
@ -2188,6 +2347,7 @@ void SystemDictionaryShared::update_archived_mirror_native_pointers() {
}
update_archived_mirror_native_pointers_for(&_builtin_dictionary);
update_archived_mirror_native_pointers_for(&_unregistered_dictionary);
update_archived_mirror_native_pointers_for(&_lambda_proxy_class_dictionary);
for (int t = T_BOOLEAN; t <= T_LONG; t++) {
Klass* k = Universe::typeArrayKlassObj((BasicType)t);

View File

@ -101,6 +101,7 @@
===============================================================================*/
#define UNREGISTERED_INDEX -9999
class BootstrapInfo;
class ClassFileStream;
class Dictionary;
class DumpTimeSharedClassInfo;
@ -220,6 +221,11 @@ private:
static bool _dump_in_progress;
DEBUG_ONLY(static bool _no_class_loading_should_happen;)
static void print_on(const char* prefix,
RunTimeSharedDictionary* builtin_dictionary,
RunTimeSharedDictionary* unregistered_dictionary,
LambdaProxyClassDictionary* lambda_dictionary,
outputStream* st) NOT_CDS_RETURN;
public:
static bool is_hidden_lambda_proxy(InstanceKlass* ik);
@ -288,7 +294,7 @@ public:
Symbol* invoked_type,
Symbol* method_type,
Method* member_method,
Symbol* instantiated_method_type) NOT_CDS_RETURN;
Symbol* instantiated_method_type, TRAPS) NOT_CDS_RETURN;
static InstanceKlass* get_shared_lambda_proxy_class(InstanceKlass* caller_ik,
Symbol* invoked_name,
Symbol* invoked_type,
@ -322,6 +328,7 @@ public:
static bool empty_dumptime_table() NOT_CDS_RETURN_(true);
static void start_dumping() NOT_CDS_RETURN;
static Handle create_jar_manifest(const char* man, size_t size, TRAPS) NOT_CDS_RETURN_(Handle());
static bool is_supported_invokedynamic(BootstrapInfo* bsi) NOT_CDS_RETURN_(false);
DEBUG_ONLY(static bool no_class_loading_should_happen() {return _no_class_loading_should_happen;})
@ -348,6 +355,7 @@ public:
#if INCLUDE_CDS_JAVA_HEAP
private:
static void update_archived_mirror_native_pointers_for(RunTimeSharedDictionary* dict);
static void update_archived_mirror_native_pointers_for(LambdaProxyClassDictionary* dict);
public:
static void update_archived_mirror_native_pointers() NOT_CDS_RETURN;
#endif

View File

@ -198,7 +198,7 @@ JVM_LookupLambdaProxyClassFromArchive(JNIEnv* env, jclass caller,
jboolean initialize);
JNIEXPORT jboolean JNICALL
JVM_IsDynamicDumpingEnabled(JNIEnv* env);
JVM_IsCDSDumpingEnabled(JNIEnv* env);
JNIEXPORT jboolean JNICALL
JVM_IsSharingEnabled(JNIEnv* env);

View File

@ -39,6 +39,7 @@
#include "interpreter/linkResolver.hpp"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/archiveUtils.hpp"
#include "memory/resourceArea.hpp"
#include "oops/constantPool.hpp"
#include "oops/cpCache.inline.hpp"
@ -1765,6 +1766,9 @@ void LinkResolver::resolve_invokedynamic(CallInfo& result, const constantPoolHan
// of this method, via CPCE::set_dynamic_call, which uses
// an ObjectLocker to do the final serialization of updates
// to CPCE state, including f1.
// Log dynamic info to CDS classlist.
ArchiveUtils::log_to_classlist(&bootstrap_specifier, THREAD);
}
void LinkResolver::resolve_dynamic_call(CallInfo& result,

View File

@ -23,12 +23,17 @@
*/
#include "precompiled.hpp"
#include "classfile/classListParser.hpp"
#include "classfile/classListWriter.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "interpreter/bootstrapInfo.hpp"
#include "memory/archiveUtils.hpp"
#include "memory/dynamicArchive.hpp"
#include "memory/filemap.hpp"
#include "memory/heapShared.inline.hpp"
#include "memory/metaspace.hpp"
#include "memory/metaspaceShared.hpp"
#include "memory/resourceArea.hpp"
#include "oops/compressedOops.inline.hpp"
#include "utilities/bitMap.inline.hpp"
@ -293,3 +298,24 @@ void ReadClosure::do_region(u_char* start, size_t size) {
size -= sizeof(intptr_t);
}
}
fileStream* ClassListWriter::_classlist_file = NULL;
void ArchiveUtils::log_to_classlist(BootstrapInfo* bootstrap_specifier, TRAPS) {
if (ClassListWriter::is_enabled()) {
if (SystemDictionaryShared::is_supported_invokedynamic(bootstrap_specifier)) {
ResourceMark rm(THREAD);
const constantPoolHandle& pool = bootstrap_specifier->pool();
int pool_index = bootstrap_specifier->bss_index();
ClassListWriter w;
w.stream()->print("%s %s", LAMBDA_PROXY_TAG, pool->pool_holder()->name()->as_C_string());
CDSIndyInfo cii;
ClassListParser::populate_cds_indy_info(pool, pool_index, &cii, THREAD);
GrowableArray<const char*>* indy_items = cii.items();
for (int i = 0; i < indy_items->length(); i++) {
w.stream()->print(" %s", indy_items->at(i));
}
w.stream()->cr();
}
}
}

View File

@ -30,6 +30,7 @@
#include "runtime/arguments.hpp"
#include "utilities/bitMap.hpp"
class BootstrapInfo;
class ReservedSpace;
class VirtualSpace;
@ -239,4 +240,9 @@ public:
bool reading() const { return true; }
};
class ArchiveUtils {
public:
static void log_to_classlist(BootstrapInfo* bootstrap_specifier, TRAPS) NOT_CDS_RETURN;
};
#endif // SHARE_MEMORY_ARCHIVEUTILS_HPP

View File

@ -776,6 +776,8 @@ void VM_PopulateDumpSharedSpace::doit() {
char* serialized_data = dump_read_only_tables();
_ro_region.pack();
SystemDictionaryShared::adjust_lambda_proxy_class_dictionary();
// The vtable clones contain addresses of the current process.
// We don't want to write these addresses into the archive. Same for i2i buffer.
CppVtables::zero_archived_vtables();

View File

@ -27,6 +27,7 @@
#include "aot/aotLoader.hpp"
#include "classfile/classFileParser.hpp"
#include "classfile/classFileStream.hpp"
#include "classfile/classListWriter.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/javaClasses.hpp"
@ -4195,7 +4196,7 @@ unsigned char * InstanceKlass::get_cached_class_file_bytes() {
void InstanceKlass::log_to_classlist(const ClassFileStream* stream) const {
#if INCLUDE_CDS
if (DumpLoadedClassList && classlist_file->is_open()) {
if (ClassListWriter::is_enabled()) {
if (!ClassLoader::has_jrt_entry()) {
warning("DumpLoadedClassList and CDS are not supported in exploded build");
DumpLoadedClassList = NULL;
@ -4208,6 +4209,11 @@ void InstanceKlass::log_to_classlist(const ClassFileStream* stream) const {
bool skip = false;
if (is_shared()) {
assert(stream == NULL, "shared class with stream");
if (is_hidden()) {
// Don't include archived lambda proxy class in the classlist.
assert(!is_non_strong_hidden(), "unexpected non-strong hidden class");
return;
}
} else {
assert(stream != NULL, "non-shared class without stream");
// skip hidden class and unsafe anonymous class.
@ -4235,8 +4241,9 @@ void InstanceKlass::log_to_classlist(const ClassFileStream* stream) const {
tty->print_cr("skip writing class %s from source %s to classlist file",
name()->as_C_string(), stream->source());
} else {
classlist_file->print_cr("%s", name()->as_C_string());
classlist_file->flush();
ClassListWriter w;
w.stream()->print_cr("%s", name()->as_C_string());
w.stream()->flush();
}
}
#endif // INCLUDE_CDS

View File

@ -618,6 +618,7 @@ void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protec
// Only recreate it if not present. A previous attempt to restore may have
// gotten an OOM later but keep the mirror if it was created.
if (java_mirror() == NULL) {
ResourceMark rm(THREAD);
log_trace(cds, mirror)("Recreate mirror for %s", external_name());
java_lang_Class::create_mirror(this, loader, module_handle, protection_domain, Handle(), CHECK);
}

View File

@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "jvm.h"
#include "classfile/classFileStream.hpp"
#include "classfile/classListWriter.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/classLoaderData.hpp"
#include "classfile/classLoaderData.inline.hpp"
@ -3742,7 +3743,7 @@ JVM_ENTRY(void, JVM_RegisterLambdaProxyClassForArchiving(JNIEnv* env,
jclass lambdaProxyClass))
JVMWrapper("JVM_RegisterLambdaProxyClassForArchiving");
#if INCLUDE_CDS
if (!DynamicDumpSharedSpaces) {
if (!Arguments::is_dumping_archive()) {
return;
}
@ -3777,7 +3778,7 @@ JVM_ENTRY(void, JVM_RegisterLambdaProxyClassForArchiving(JNIEnv* env,
Symbol* instantiated_method_type = java_lang_invoke_MethodType::as_signature(instantiated_method_type_oop(), true);
SystemDictionaryShared::add_lambda_proxy_class(caller_ik, lambda_ik, invoked_name, invoked_type,
method_type, m, instantiated_method_type);
method_type, m, instantiated_method_type, THREAD);
#endif // INCLUDE_CDS
JVM_END
@ -3791,9 +3792,6 @@ JVM_ENTRY(jclass, JVM_LookupLambdaProxyClassFromArchive(JNIEnv* env,
jboolean initialize))
JVMWrapper("JVM_LookupLambdaProxyClassFromArchive");
#if INCLUDE_CDS
if (!DynamicArchive::is_mapped()) {
return NULL;
}
if (invokedName == NULL || invokedType == NULL || methodType == NULL ||
implMethodMember == NULL || instantiatedMethodType == NULL) {
@ -3834,9 +3832,9 @@ JVM_ENTRY(jclass, JVM_LookupLambdaProxyClassFromArchive(JNIEnv* env,
#endif // INCLUDE_CDS
JVM_END
JVM_ENTRY(jboolean, JVM_IsDynamicDumpingEnabled(JNIEnv* env))
JVMWrapper("JVM_IsDynamicDumpingEnable");
return DynamicDumpSharedSpaces;
JVM_ENTRY(jboolean, JVM_IsCDSDumpingEnabled(JNIEnv* env))
JVMWrapper("JVM_IsCDSDumpingEnabled");
return Arguments::is_dumping_archive();
JVM_END
JVM_ENTRY(jboolean, JVM_IsSharingEnabled(JNIEnv* env))
@ -3870,7 +3868,7 @@ JVM_END
JVM_ENTRY(jboolean, JVM_IsDumpingClassList(JNIEnv *env))
JVMWrapper("JVM_IsDumpingClassList");
#if INCLUDE_CDS
return DumpLoadedClassList != NULL && classlist_file != NULL && classlist_file->is_open();
return ClassListWriter::is_enabled();
#else
return false;
#endif // INCLUDE_CDS
@ -3879,12 +3877,13 @@ 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");
assert(ClassListWriter::is_enabled(), "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);
ClassListWriter w;
w.stream()->print_cr("%s %s", LambdaFormInvokers::lambda_form_invoker_tag(), c_line);
}
#endif // INCLUDE_CDS
JVM_END

View File

@ -151,6 +151,7 @@ Mutex* CDSClassFileStream_lock = NULL;
Mutex* DumpTimeTable_lock = NULL;
Mutex* CDSLambda_lock = NULL;
Mutex* DumpRegion_lock = NULL;
Mutex* ClassListFile_lock = NULL;
#endif // INCLUDE_CDS
#if INCLUDE_JVMCI
@ -343,6 +344,7 @@ void mutex_init() {
def(DumpTimeTable_lock , PaddedMutex , leaf - 1, true, _safepoint_check_never);
def(CDSLambda_lock , PaddedMutex , leaf, true, _safepoint_check_never);
def(DumpRegion_lock , PaddedMutex , leaf, true, _safepoint_check_never);
def(ClassListFile_lock , PaddedMutex , leaf, true, _safepoint_check_never);
#endif // INCLUDE_CDS
#if INCLUDE_JVMCI

View File

@ -130,6 +130,7 @@ extern Mutex* CDSClassFileStream_lock; // FileMapInfo::open_stream_for
extern Mutex* DumpTimeTable_lock; // SystemDictionaryShared::find_or_allocate_info_for
extern Mutex* CDSLambda_lock; // SystemDictionaryShared::get_shared_lambda_proxy_class
extern Mutex* DumpRegion_lock; // Symbol::operator new(size_t sz, int len)
extern Mutex* ClassListFile_lock; // ClassListWriter()
#endif // INCLUDE_CDS
#if INCLUDE_JFR
extern Mutex* JfrStacktrace_lock; // used to guard access to the JFR stacktrace table

View File

@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "jvm.h"
#include "classfile/classListWriter.hpp"
#include "compiler/compileLog.hpp"
#include "memory/allocation.inline.hpp"
#include "oops/oop.inline.hpp"
@ -390,7 +391,6 @@ stringStream::~stringStream() {
xmlStream* xtty;
outputStream* tty;
CDS_ONLY(fileStream* classlist_file;) // Only dump the classes that can be stored into the CDS archive
extern Mutex* tty_lock;
#define EXTRACHARLEN 32
@ -509,7 +509,7 @@ static const char* make_log_name_internal(const char* log_name, const char* forc
// -XX:DumpLoadedClassList=<file_name>
// in log_name, %p => pid1234 and
// %t => YYYY-MM-DD_HH-MM-SS
static const char* make_log_name(const char* log_name, const char* force_directory) {
const char* make_log_name(const char* log_name, const char* force_directory) {
char timestr[32];
get_datetime_string(timestr, sizeof(timestr));
return make_log_name_internal(log_name, force_directory, os::current_process_id(),
@ -911,15 +911,7 @@ void ostream_init() {
void ostream_init_log() {
// Note : this must be called AFTER ostream_init()
#if INCLUDE_CDS
// For -XX:DumpLoadedClassList=<file> option
if (DumpLoadedClassList != NULL) {
const char* list_name = make_log_name(DumpLoadedClassList, NULL);
classlist_file = new(ResourceObj::C_HEAP, mtInternal)
fileStream(list_name);
FREE_C_HEAP_ARRAY(char, list_name);
}
#endif
ClassListWriter::init();
// If we haven't lazily initialized the logfile yet, do it now,
// to avoid the possibility of lazy initialization during a VM
@ -933,11 +925,7 @@ void ostream_exit() {
static bool ostream_exit_called = false;
if (ostream_exit_called) return;
ostream_exit_called = true;
#if INCLUDE_CDS
if (classlist_file != NULL) {
delete classlist_file;
}
#endif
ClassListWriter::delete_classlist();
if (tty != defaultStream::instance) {
delete tty;
}

View File

@ -239,8 +239,6 @@ class fileStream : public outputStream {
void flush();
};
CDS_ONLY(extern fileStream* classlist_file;)
// unlike fileStream, fdStream does unbuffered I/O by calling
// open() and write() directly. It is async-safe, but output
// from multiple thread may be mixed together. Used by fatal
@ -261,6 +259,7 @@ void ostream_init();
void ostream_init_log();
void ostream_exit();
void ostream_abort();
const char* make_log_name(const char* log_name, const char* force_directory);
// In the non-fixed buffer case an underlying buffer will be created and
// managed in C heap. Not MT-safe.

View File

@ -25,6 +25,7 @@
package java.lang.invoke;
import jdk.internal.misc.CDS;
import jdk.internal.org.objectweb.asm.*;
import sun.invoke.util.BytecodeDescriptor;
import sun.security.action.GetPropertyAction;
@ -263,7 +264,7 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
*/
private Class<?> spinInnerClass() throws LambdaConversionException {
// include lambda proxy class in CDS archive at dump time
if (LambdaProxyClassArchive.isDumpArchive()) {
if (CDS.isDumpingArchive()) {
Class<?> innerClass = generateInnerClass();
LambdaProxyClassArchive.register(targetClass,
samMethodName,

View File

@ -29,28 +29,6 @@ import jdk.internal.loader.BuiltinClassLoader;
import jdk.internal.misc.CDS;
final class LambdaProxyClassArchive {
private static final boolean dumpArchive;
private static final boolean sharingEnabled;
static {
dumpArchive = CDS.isDynamicDumpingEnabled();
sharingEnabled = CDS.isSharingEnabled();
}
/**
* Check if CDS dynamic dump is enabled.
*/
static boolean isDumpArchive() {
return dumpArchive;
}
/**
* Check if CDS sharing is enabled.
*/
static boolean isSharingEnabled() {
return sharingEnabled;
}
/**
* Check if the class is loaded by a built-in class loader.
*/
@ -94,7 +72,7 @@ final class LambdaProxyClassArchive {
Class<?>[] markerInterfaces,
MethodType[] additionalBridges,
Class<?> lambdaProxyClass) {
if (!isDumpArchive())
if (!CDS.isDumpingArchive())
throw new IllegalStateException("should only register lambda proxy class at dump time");
if (loadedByBuiltinLoader(caller) &&
@ -125,11 +103,11 @@ final class LambdaProxyClassArchive {
Class<?>[] markerInterfaces,
MethodType[] additionalBridges,
boolean initialize) {
if (isDumpArchive())
if (CDS.isDumpingArchive())
throw new IllegalStateException("cannot load class from CDS archive at dump time");
if (!loadedByBuiltinLoader(caller) ||
!isSharingEnabled() || isSerializable || markerInterfaces.length > 0 || additionalBridges.length > 0)
if (!loadedByBuiltinLoader(caller) || !initialize ||
!CDS.isSharingEnabled() || isSerializable || markerInterfaces.length > 0 || additionalBridges.length > 0)
return null;
return findFromArchive(caller, invokedName, invokedType, samMethodType,

View File

@ -35,8 +35,12 @@ import jdk.internal.access.SharedSecrets;
public class CDS {
private static final boolean isDumpingClassList;
private static final boolean isDumpingArchive;
private static final boolean isSharingEnabled;
static {
isDumpingClassList = isDumpingClassList0();
isDumpingArchive = isDumpingArchive0();
isSharingEnabled = isSharingEnabled0();
}
/**
@ -45,7 +49,23 @@ public class CDS {
public static boolean isDumpingClassList() {
return isDumpingClassList;
}
/**
* Is the VM writing to a (static or dynamic) CDS archive.
*/
public static boolean isDumpingArchive() {
return isDumpingArchive;
}
/**
* Is sharing enabled via the UseSharedSpaces flag.
*/
public static boolean isSharingEnabled() {
return isSharingEnabled;
}
private static native boolean isDumpingClassList0();
private static native boolean isDumpingArchive0();
private static native boolean isSharingEnabled0();
private static native void logLambdaFormInvoker(String line);
/**
@ -72,16 +92,6 @@ public class CDS {
*/
public static native long getRandomSeedForDumping();
/**
* Check if dynamic dumping is enabled via the DynamicDumpSharedSpaces flag.
*/
public static native boolean isDynamicDumpingEnabled(); // will return false for static dumping.
/**
* Check if sharing is enabled via the UseSharedSpaces flag.
*/
public static native boolean isSharingEnabled();
/**
* log lambda form invoker holder, name and method type
*/

View File

@ -45,12 +45,12 @@ Java_jdk_internal_misc_CDS_getRandomSeedForDumping(JNIEnv *env, jclass ignore) {
}
JNIEXPORT jboolean JNICALL
Java_jdk_internal_misc_CDS_isDynamicDumpingEnabled(JNIEnv *env, jclass jcls) {
return JVM_IsDynamicDumpingEnabled(env);
Java_jdk_internal_misc_CDS_isDumpingArchive0(JNIEnv *env, jclass jcls) {
return JVM_IsCDSDumpingEnabled(env);
}
JNIEXPORT jboolean JNICALL
Java_jdk_internal_misc_CDS_isSharingEnabled(JNIEnv *env, jclass jcls) {
Java_jdk_internal_misc_CDS_isSharingEnabled0(JNIEnv *env, jclass jcls) {
return JVM_IsSharingEnabled(env);
}

View File

@ -327,16 +327,20 @@ hotspot_appcds_dynamic = \
-runtime/cds/appcds/javaldr/GCSharedStringsDuringDump.java \
-runtime/cds/appcds/javaldr/HumongousDuringDump.java \
-runtime/cds/appcds/javaldr/LockDuringDump.java \
-runtime/cds/appcds/methodHandles \
-runtime/cds/appcds/sharedStrings \
-runtime/cds/appcds/ArchiveRelocationTest.java \
-runtime/cds/appcds/BadBSM.java \
-runtime/cds/appcds/DumpClassList.java \
-runtime/cds/appcds/DumpClassListWithLF.java \
-runtime/cds/appcds/ExtraSymbols.java \
-runtime/cds/appcds/LambdaProxyClasslist.java \
-runtime/cds/appcds/LongClassListPath.java \
-runtime/cds/appcds/LotsOfClasses.java \
-runtime/cds/appcds/NonExistClasspath.java \
-runtime/cds/appcds/RelativePath.java \
-runtime/cds/appcds/SharedArchiveConsistency.java \
-runtime/cds/appcds/StaticArchiveWithLambda.java \
-runtime/cds/appcds/TestCombinedCompressedFlags.java \
-runtime/cds/appcds/TestZGCWithCDS.java \
-runtime/cds/appcds/UnusedCPDuringDump.java \

View File

@ -0,0 +1,49 @@
/*
* 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 CDS dump should abort if a class file contains a bad BSM.
* @requires vm.cds
* @library /test/lib
* @compile test-classes/WrongBSM.jcod
* @run driver BadBSM
*/
import jdk.test.lib.process.OutputAnalyzer;
public class BadBSM {
public static void main(String[] args) throws Exception {
JarBuilder.build("wrongbsm", "WrongBSM");
String appJar = TestCommon.getTestJar("wrongbsm.jar");
OutputAnalyzer out = TestCommon.dump(appJar,
TestCommon.list("WrongBSM",
"@lambda-proxy: WrongBSM 7"));
out.shouldHaveExitValue(0);
out.shouldContain( "is_supported_invokedynamic check failed for cp_index 7");
}
}

View File

@ -0,0 +1,77 @@
/*
* 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 some error handling on the "@lambda-proxy" entries in a classlist.
* @requires vm.cds
* @library /test/lib
* @compile dynamicArchive/test-classes/LambHello.java
* @run driver LambdaProxyClasslist
*/
import jdk.test.lib.process.OutputAnalyzer;
public class LambdaProxyClasslist {
public static void main(String[] args) throws Exception {
JarBuilder.build("lambhello", "LambHello");
String appJar = TestCommon.getTestJar("lambhello.jar");
// 1. No error with a correct @lambda-proxy entry.
OutputAnalyzer out = TestCommon.dump(appJar,
TestCommon.list("LambHello",
"@lambda-proxy: LambHello run ()Ljava/lang/Runnable; ()V REF_invokeStatic LambHello lambda$doTest$0 ()V ()V"));
out.shouldHaveExitValue(0);
// 2. Error if the @lambda-proxy entry is too short.
out = TestCommon.dump(appJar,
TestCommon.list("LambHello",
"@lambda-proxy: LambHello"));
out.shouldContain("An error has occurred while processing class list file")
.shouldContain("Line with @ tag has too few items \"@lambda-proxy:\" line #2")
.shouldContain("class list format error")
.shouldHaveExitValue(1);
// 3. Warning message if there's an incorrect signature in the @lambda-proxy entry.
out = TestCommon.dump(appJar,
TestCommon.list("LambHello",
"@lambda-proxy: LambHello run ()Ljava/lang/Runnable; ()V REF_invokeStatic LambHello lambda$doTest$0 ()V ()Z"));
out.shouldContain("[warning][cds] No invoke dynamic constant pool entry can be found for class LambHello. The classlist is probably out-of-date.")
.shouldHaveExitValue(0);
// 4. More blank spaces in between items should be fine.
out = TestCommon.dump(appJar,
TestCommon.list("LambHello",
"@lambda-proxy: LambHello run ()Ljava/lang/Runnable; ()V REF_invokeStatic LambHello lambda$doTest$0 ()V ()V"));
out.shouldHaveExitValue(0);
// 5. Trailing spaces at the end of the @lambda-proxy line should be fine.
out = TestCommon.dump(appJar,
TestCommon.list("LambHello",
"@lambda-proxy: LambHello run ()Ljava/lang/Runnable; ()V REF_invokeStatic LambHello lambda$doTest$0 ()V ()V "));
out.shouldHaveExitValue(0);
}
}

View File

@ -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 Sanity test lambda proxy classes in static CDS archive.
* @requires vm.cds
* @library /test/lib
* @compile dynamicArchive/test-classes/LambHello.java
* @run driver StaticArchiveWithLambda
*/
import jdk.test.lib.cds.CDSOptions;
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
public class StaticArchiveWithLambda {
public static void main(String[] args) throws Exception {
String appClass = "LambHello";
JarBuilder.build("lambhello", appClass);
String appJar = TestCommon.getTestJar("lambhello.jar");
String classList = "lambhello.list";
String archiveName = "StaticArchiveWithLambda.jsa";
// dump class list
ProcessBuilder pb = ProcessTools.createTestJvm(
"-XX:DumpLoadedClassList=" + classList,
"-cp", appJar,
appClass);
OutputAnalyzer output = TestCommon.executeAndLog(pb, "dumpClassList");
// create archive with the class list
CDSOptions opts = (new CDSOptions())
.addPrefix("-XX:ExtraSharedClassListFile=" + classList,
"-cp", appJar,
"-Xlog:class+load,cds")
.setArchiveName(archiveName);
CDSTestUtils.createArchiveAndCheck(opts);
// run with archive
CDSOptions runOpts = (new CDSOptions())
.addPrefix("-cp", appJar, "-Xlog:class+load,cds=debug")
.setArchiveName(archiveName)
.setUseVersion(false)
.addSuffix(appClass);
output = CDSTestUtils.runWithArchive(runOpts);
output.shouldContain("LambHello source: shared objects file")
.shouldMatch("class.load.*LambHello[$][$]Lambda[$].*0x.*source:.shared.objects.file")
.shouldHaveExitValue(0);
}
}

View File

@ -0,0 +1,98 @@
/*
* 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 Archive lambda proxy class is in the base archive. The lambda proxy
* class should be loaded from the base archive during runtime.
*
* @requires vm.cds
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds /test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes
* @build LambHello
* @build sun.hotspot.WhiteBox
* @run driver ClassFileInstaller -jar lambhello.jar LambHello
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. LambdaInBaseArchive
*/
import jdk.test.lib.cds.CDSOptions;
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
public class LambdaInBaseArchive extends DynamicArchiveTestBase {
public static void main(String[] args) throws Exception {
createBaseArchive();
runTest(LambdaInBaseArchive::testCustomBase);
}
static String helloBaseArchive = getNewArchiveName("base-with-hello");
static String appJar = ClassFileInstaller.getJarPath("lambhello.jar");
static String mainClass = "LambHello";
static String classList = "lambhello.list";
static void createBaseArchive() throws Exception {
// dump class list
ProcessBuilder pb = ProcessTools.createTestJvm(
"-XX:DumpLoadedClassList=" + classList,
"-cp", appJar,
mainClass);
OutputAnalyzer output = TestCommon.executeAndLog(pb, "dumpClassList");
output.shouldHaveExitValue(0);
// create archive with the class list
CDSOptions opts = (new CDSOptions())
.addPrefix("-XX:ExtraSharedClassListFile=" + classList,
"-cp", appJar,
"-Xlog:class+load,cds")
.setArchiveName(helloBaseArchive);
CDSTestUtils.createArchiveAndCheck(opts);
}
// Test with custom base archive + top archive
static void testCustomBase() throws Exception {
String topArchiveName = getNewArchiveName("top2");
doTest(helloBaseArchive, topArchiveName);
}
private static void doTest(String baseArchiveName, String topArchiveName) throws Exception {
dump2(baseArchiveName, topArchiveName,
"-Xlog:class+load,cds,cds+dynamic=debug",
"-cp", appJar, mainClass)
.assertNormalExit(output -> {
output.shouldContain("Buffer-space to target-space delta")
.shouldContain("Written dynamic archive 0x");
});
run2(baseArchiveName, topArchiveName,
"-Xlog:class+load,cds+dynamic=debug,cds=debug",
"-cp", appJar, mainClass)
.assertNormalExit(output -> {
output.shouldContain("LambHello source: shared objects file")
.shouldMatch("class.load.*LambHello[$][$]Lambda[$].*0x.*source:.shared.objects.file")
.shouldNotMatch("class.load.*LambHello[$][$]Lambda[$].*0x.*source:.shared.objects.file.*(top)");
});
}
}

View File

@ -48,7 +48,8 @@ public class CustomLoaderApp {
", expected == " + urlClassLoader);
}
Method method = c.getDeclaredMethod("doTest");
method.invoke(o);
Method method = c.getMethod("main", String[].class);
String[] params = null;
method.invoke(null, (Object)params);
}
}

View File

@ -23,9 +23,10 @@
*/
public class LambHello {
public static void main(String[] args) {
doTest();
}
public void doTest() {
static void doTest() {
doit(() -> {
System.out.println("Hello from doTest");
});

View File

@ -0,0 +1,144 @@
#!/bin/bash
# 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.
#
echo "// --- start auto-generated"
testnames=( MethodHandlesGeneralTest MethodHandlesAsCollectorTest MethodHandlesCastFailureTest MethodHandlesInvokersTest MethodHandlesPermuteArgumentsTest MethodHandlesSpreadArgumentsTest )
name_suffix='.java'
for i in "${testnames[@]}"
do
fname="$i$name_suffix"
cat << EOF > $fname
/*
* 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.
*
*/
// this file is auto-generated by $0. Do not edit manually.
/*
* @test
* @summary Run the $fname test in static CDS archive mode.
* @requires vm.cds & vm.compMode != "Xcomp"
* @comment Some of the tests run excessively slowly with -Xcomp. The original
* tests aren't executed with -Xcomp in the CI pipeline, so let's exclude
* the generated tests from -Xcomp execution as well.
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
* /test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes
* @compile ../../../../../../jdk/java/lang/invoke/MethodHandlesTest.java
* ../../../../../../lib/jdk/test/lib/Utils.java
* ../../../../../../jdk/java/lang/invoke/$fname
* ../../../../../../jdk/java/lang/invoke/remote/RemoteExample.java
* ../../../../../../jdk/java/lang/invoke/common/test/java/lang/invoke/lib/CodeCacheOverflowProcessor.java
* ../dynamicArchive/test-classes/TestMHApp.java
* @build sun.hotspot.WhiteBox
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
* @run junit/othervm/timeout=480 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. $i
*/
import org.junit.Test;
import java.io.File;
import jdk.test.lib.cds.CDSOptions;
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
public class $i {
@Test
public void test() throws Exception {
testImpl();
}
private static final String classDir = System.getProperty("test.classes");
private static final String mainClass = "TestMHApp";
private static final String javaClassPath = System.getProperty("java.class.path");
private static final String ps = System.getProperty("path.separator");
private static final String testPackageName = "test.java.lang.invoke";
private static final String testClassName = "$i";
static void testImpl() throws Exception {
String appJar = JarBuilder.build("MH", new File(classDir), null);
String classList = testClassName + ".list";
String archiveName = testClassName + ".jsa";
String[] classPaths = javaClassPath.split(File.pathSeparator);
String junitJar = null;
for (String path : classPaths) {
if (path.endsWith("junit.jar")) {
junitJar = path;
break;
}
}
String jars = appJar + ps + junitJar;
// dump class list
ProcessBuilder pb = ProcessTools.createTestJvm(
"-XX:DumpLoadedClassList=" + classList,
"-cp", jars,
mainClass, testPackageName + "." + testClassName);
OutputAnalyzer output = TestCommon.executeAndLog(pb, "dumpClassList");
// create archive with the class list
CDSOptions opts = (new CDSOptions())
.addPrefix("-XX:ExtraSharedClassListFile=" + classList,
"-cp", jars,
"-Xlog:class+load,cds")
.setArchiveName(archiveName);
CDSTestUtils.createArchiveAndCheck(opts);
// run with archive
CDSOptions runOpts = (new CDSOptions())
.addPrefix("-cp", jars, "-Xlog:class+load,cds=debug")
.setArchiveName(archiveName)
.setUseVersion(false)
.addSuffix(mainClass, testPackageName + "." + testClassName);
output = CDSTestUtils.runWithArchive(runOpts);
output.shouldMatch(".class.load. test.java.lang.invoke.$i[$][$]Lambda[$].*/0x.*source:.*shared.*objects.*file")
.shouldHaveExitValue(0);
}
}
EOF
done
echo "// --- end auto-generated"

View 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.
*
*/
// this file is auto-generated by ./CDSMHTest_generate.sh. Do not edit manually.
/*
* @test
* @summary Run the MethodHandlesAsCollectorTest.java test in static CDS archive mode.
* @requires vm.cds & vm.compMode != "Xcomp"
* @comment Some of the tests run excessively slowly with -Xcomp. The original
* tests aren't executed with -Xcomp in the CI pipeline, so let's exclude
* the generated tests from -Xcomp execution as well.
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
* /test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes
* @compile ../../../../../../jdk/java/lang/invoke/MethodHandlesTest.java
* ../../../../../../lib/jdk/test/lib/Utils.java
* ../../../../../../jdk/java/lang/invoke/MethodHandlesAsCollectorTest.java
* ../../../../../../jdk/java/lang/invoke/remote/RemoteExample.java
* ../../../../../../jdk/java/lang/invoke/common/test/java/lang/invoke/lib/CodeCacheOverflowProcessor.java
* ../dynamicArchive/test-classes/TestMHApp.java
* @build sun.hotspot.WhiteBox
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
* @run junit/othervm/timeout=480 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. MethodHandlesAsCollectorTest
*/
import org.junit.Test;
import java.io.File;
import jdk.test.lib.cds.CDSOptions;
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
public class MethodHandlesAsCollectorTest {
@Test
public void test() throws Exception {
testImpl();
}
private static final String classDir = System.getProperty("test.classes");
private static final String mainClass = "TestMHApp";
private static final String javaClassPath = System.getProperty("java.class.path");
private static final String ps = System.getProperty("path.separator");
private static final String testPackageName = "test.java.lang.invoke";
private static final String testClassName = "MethodHandlesAsCollectorTest";
static void testImpl() throws Exception {
String appJar = JarBuilder.build("MH", new File(classDir), null);
String classList = testClassName + ".list";
String archiveName = testClassName + ".jsa";
String[] classPaths = javaClassPath.split(File.pathSeparator);
String junitJar = null;
for (String path : classPaths) {
if (path.endsWith("junit.jar")) {
junitJar = path;
break;
}
}
String jars = appJar + ps + junitJar;
// dump class list
ProcessBuilder pb = ProcessTools.createTestJvm(
"-XX:DumpLoadedClassList=" + classList,
"-cp", jars,
mainClass, testPackageName + "." + testClassName);
OutputAnalyzer output = TestCommon.executeAndLog(pb, "dumpClassList");
// create archive with the class list
CDSOptions opts = (new CDSOptions())
.addPrefix("-XX:ExtraSharedClassListFile=" + classList,
"-cp", jars,
"-Xlog:class+load,cds")
.setArchiveName(archiveName);
CDSTestUtils.createArchiveAndCheck(opts);
// run with archive
CDSOptions runOpts = (new CDSOptions())
.addPrefix("-cp", jars, "-Xlog:class+load,cds=debug")
.setArchiveName(archiveName)
.setUseVersion(false)
.addSuffix(mainClass, testPackageName + "." + testClassName);
output = CDSTestUtils.runWithArchive(runOpts);
output.shouldMatch(".class.load. test.java.lang.invoke.MethodHandlesAsCollectorTest[$][$]Lambda[$].*/0x.*source:.*shared.*objects.*file")
.shouldHaveExitValue(0);
}
}

View 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.
*
*/
// this file is auto-generated by ./CDSMHTest_generate.sh. Do not edit manually.
/*
* @test
* @summary Run the MethodHandlesCastFailureTest.java test in static CDS archive mode.
* @requires vm.cds & vm.compMode != "Xcomp"
* @comment Some of the tests run excessively slowly with -Xcomp. The original
* tests aren't executed with -Xcomp in the CI pipeline, so let's exclude
* the generated tests from -Xcomp execution as well.
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
* /test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes
* @compile ../../../../../../jdk/java/lang/invoke/MethodHandlesTest.java
* ../../../../../../lib/jdk/test/lib/Utils.java
* ../../../../../../jdk/java/lang/invoke/MethodHandlesCastFailureTest.java
* ../../../../../../jdk/java/lang/invoke/remote/RemoteExample.java
* ../../../../../../jdk/java/lang/invoke/common/test/java/lang/invoke/lib/CodeCacheOverflowProcessor.java
* ../dynamicArchive/test-classes/TestMHApp.java
* @build sun.hotspot.WhiteBox
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
* @run junit/othervm/timeout=480 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. MethodHandlesCastFailureTest
*/
import org.junit.Test;
import java.io.File;
import jdk.test.lib.cds.CDSOptions;
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
public class MethodHandlesCastFailureTest {
@Test
public void test() throws Exception {
testImpl();
}
private static final String classDir = System.getProperty("test.classes");
private static final String mainClass = "TestMHApp";
private static final String javaClassPath = System.getProperty("java.class.path");
private static final String ps = System.getProperty("path.separator");
private static final String testPackageName = "test.java.lang.invoke";
private static final String testClassName = "MethodHandlesCastFailureTest";
static void testImpl() throws Exception {
String appJar = JarBuilder.build("MH", new File(classDir), null);
String classList = testClassName + ".list";
String archiveName = testClassName + ".jsa";
String[] classPaths = javaClassPath.split(File.pathSeparator);
String junitJar = null;
for (String path : classPaths) {
if (path.endsWith("junit.jar")) {
junitJar = path;
break;
}
}
String jars = appJar + ps + junitJar;
// dump class list
ProcessBuilder pb = ProcessTools.createTestJvm(
"-XX:DumpLoadedClassList=" + classList,
"-cp", jars,
mainClass, testPackageName + "." + testClassName);
OutputAnalyzer output = TestCommon.executeAndLog(pb, "dumpClassList");
// create archive with the class list
CDSOptions opts = (new CDSOptions())
.addPrefix("-XX:ExtraSharedClassListFile=" + classList,
"-cp", jars,
"-Xlog:class+load,cds")
.setArchiveName(archiveName);
CDSTestUtils.createArchiveAndCheck(opts);
// run with archive
CDSOptions runOpts = (new CDSOptions())
.addPrefix("-cp", jars, "-Xlog:class+load,cds=debug")
.setArchiveName(archiveName)
.setUseVersion(false)
.addSuffix(mainClass, testPackageName + "." + testClassName);
output = CDSTestUtils.runWithArchive(runOpts);
output.shouldMatch(".class.load. test.java.lang.invoke.MethodHandlesCastFailureTest[$][$]Lambda[$].*/0x.*source:.*shared.*objects.*file")
.shouldHaveExitValue(0);
}
}

View 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.
*
*/
// this file is auto-generated by ./CDSMHTest_generate.sh. Do not edit manually.
/*
* @test
* @summary Run the MethodHandlesGeneralTest.java test in static CDS archive mode.
* @requires vm.cds & vm.compMode != "Xcomp"
* @comment Some of the tests run excessively slowly with -Xcomp. The original
* tests aren't executed with -Xcomp in the CI pipeline, so let's exclude
* the generated tests from -Xcomp execution as well.
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
* /test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes
* @compile ../../../../../../jdk/java/lang/invoke/MethodHandlesTest.java
* ../../../../../../lib/jdk/test/lib/Utils.java
* ../../../../../../jdk/java/lang/invoke/MethodHandlesGeneralTest.java
* ../../../../../../jdk/java/lang/invoke/remote/RemoteExample.java
* ../../../../../../jdk/java/lang/invoke/common/test/java/lang/invoke/lib/CodeCacheOverflowProcessor.java
* ../dynamicArchive/test-classes/TestMHApp.java
* @build sun.hotspot.WhiteBox
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
* @run junit/othervm/timeout=480 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. MethodHandlesGeneralTest
*/
import org.junit.Test;
import java.io.File;
import jdk.test.lib.cds.CDSOptions;
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
public class MethodHandlesGeneralTest {
@Test
public void test() throws Exception {
testImpl();
}
private static final String classDir = System.getProperty("test.classes");
private static final String mainClass = "TestMHApp";
private static final String javaClassPath = System.getProperty("java.class.path");
private static final String ps = System.getProperty("path.separator");
private static final String testPackageName = "test.java.lang.invoke";
private static final String testClassName = "MethodHandlesGeneralTest";
static void testImpl() throws Exception {
String appJar = JarBuilder.build("MH", new File(classDir), null);
String classList = testClassName + ".list";
String archiveName = testClassName + ".jsa";
String[] classPaths = javaClassPath.split(File.pathSeparator);
String junitJar = null;
for (String path : classPaths) {
if (path.endsWith("junit.jar")) {
junitJar = path;
break;
}
}
String jars = appJar + ps + junitJar;
// dump class list
ProcessBuilder pb = ProcessTools.createTestJvm(
"-XX:DumpLoadedClassList=" + classList,
"-cp", jars,
mainClass, testPackageName + "." + testClassName);
OutputAnalyzer output = TestCommon.executeAndLog(pb, "dumpClassList");
// create archive with the class list
CDSOptions opts = (new CDSOptions())
.addPrefix("-XX:ExtraSharedClassListFile=" + classList,
"-cp", jars,
"-Xlog:class+load,cds")
.setArchiveName(archiveName);
CDSTestUtils.createArchiveAndCheck(opts);
// run with archive
CDSOptions runOpts = (new CDSOptions())
.addPrefix("-cp", jars, "-Xlog:class+load,cds=debug")
.setArchiveName(archiveName)
.setUseVersion(false)
.addSuffix(mainClass, testPackageName + "." + testClassName);
output = CDSTestUtils.runWithArchive(runOpts);
output.shouldMatch(".class.load. test.java.lang.invoke.MethodHandlesGeneralTest[$][$]Lambda[$].*/0x.*source:.*shared.*objects.*file")
.shouldHaveExitValue(0);
}
}

View 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.
*
*/
// this file is auto-generated by ./CDSMHTest_generate.sh. Do not edit manually.
/*
* @test
* @summary Run the MethodHandlesInvokersTest.java test in static CDS archive mode.
* @requires vm.cds & vm.compMode != "Xcomp"
* @comment Some of the tests run excessively slowly with -Xcomp. The original
* tests aren't executed with -Xcomp in the CI pipeline, so let's exclude
* the generated tests from -Xcomp execution as well.
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
* /test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes
* @compile ../../../../../../jdk/java/lang/invoke/MethodHandlesTest.java
* ../../../../../../lib/jdk/test/lib/Utils.java
* ../../../../../../jdk/java/lang/invoke/MethodHandlesInvokersTest.java
* ../../../../../../jdk/java/lang/invoke/remote/RemoteExample.java
* ../../../../../../jdk/java/lang/invoke/common/test/java/lang/invoke/lib/CodeCacheOverflowProcessor.java
* ../dynamicArchive/test-classes/TestMHApp.java
* @build sun.hotspot.WhiteBox
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
* @run junit/othervm/timeout=480 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. MethodHandlesInvokersTest
*/
import org.junit.Test;
import java.io.File;
import jdk.test.lib.cds.CDSOptions;
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
public class MethodHandlesInvokersTest {
@Test
public void test() throws Exception {
testImpl();
}
private static final String classDir = System.getProperty("test.classes");
private static final String mainClass = "TestMHApp";
private static final String javaClassPath = System.getProperty("java.class.path");
private static final String ps = System.getProperty("path.separator");
private static final String testPackageName = "test.java.lang.invoke";
private static final String testClassName = "MethodHandlesInvokersTest";
static void testImpl() throws Exception {
String appJar = JarBuilder.build("MH", new File(classDir), null);
String classList = testClassName + ".list";
String archiveName = testClassName + ".jsa";
String[] classPaths = javaClassPath.split(File.pathSeparator);
String junitJar = null;
for (String path : classPaths) {
if (path.endsWith("junit.jar")) {
junitJar = path;
break;
}
}
String jars = appJar + ps + junitJar;
// dump class list
ProcessBuilder pb = ProcessTools.createTestJvm(
"-XX:DumpLoadedClassList=" + classList,
"-cp", jars,
mainClass, testPackageName + "." + testClassName);
OutputAnalyzer output = TestCommon.executeAndLog(pb, "dumpClassList");
// create archive with the class list
CDSOptions opts = (new CDSOptions())
.addPrefix("-XX:ExtraSharedClassListFile=" + classList,
"-cp", jars,
"-Xlog:class+load,cds")
.setArchiveName(archiveName);
CDSTestUtils.createArchiveAndCheck(opts);
// run with archive
CDSOptions runOpts = (new CDSOptions())
.addPrefix("-cp", jars, "-Xlog:class+load,cds=debug")
.setArchiveName(archiveName)
.setUseVersion(false)
.addSuffix(mainClass, testPackageName + "." + testClassName);
output = CDSTestUtils.runWithArchive(runOpts);
output.shouldMatch(".class.load. test.java.lang.invoke.MethodHandlesInvokersTest[$][$]Lambda[$].*/0x.*source:.*shared.*objects.*file")
.shouldHaveExitValue(0);
}
}

View 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.
*
*/
// this file is auto-generated by ./CDSMHTest_generate.sh. Do not edit manually.
/*
* @test
* @summary Run the MethodHandlesPermuteArgumentsTest.java test in static CDS archive mode.
* @requires vm.cds & vm.compMode != "Xcomp"
* @comment Some of the tests run excessively slowly with -Xcomp. The original
* tests aren't executed with -Xcomp in the CI pipeline, so let's exclude
* the generated tests from -Xcomp execution as well.
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
* /test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes
* @compile ../../../../../../jdk/java/lang/invoke/MethodHandlesTest.java
* ../../../../../../lib/jdk/test/lib/Utils.java
* ../../../../../../jdk/java/lang/invoke/MethodHandlesPermuteArgumentsTest.java
* ../../../../../../jdk/java/lang/invoke/remote/RemoteExample.java
* ../../../../../../jdk/java/lang/invoke/common/test/java/lang/invoke/lib/CodeCacheOverflowProcessor.java
* ../dynamicArchive/test-classes/TestMHApp.java
* @build sun.hotspot.WhiteBox
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
* @run junit/othervm/timeout=480 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. MethodHandlesPermuteArgumentsTest
*/
import org.junit.Test;
import java.io.File;
import jdk.test.lib.cds.CDSOptions;
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
public class MethodHandlesPermuteArgumentsTest {
@Test
public void test() throws Exception {
testImpl();
}
private static final String classDir = System.getProperty("test.classes");
private static final String mainClass = "TestMHApp";
private static final String javaClassPath = System.getProperty("java.class.path");
private static final String ps = System.getProperty("path.separator");
private static final String testPackageName = "test.java.lang.invoke";
private static final String testClassName = "MethodHandlesPermuteArgumentsTest";
static void testImpl() throws Exception {
String appJar = JarBuilder.build("MH", new File(classDir), null);
String classList = testClassName + ".list";
String archiveName = testClassName + ".jsa";
String[] classPaths = javaClassPath.split(File.pathSeparator);
String junitJar = null;
for (String path : classPaths) {
if (path.endsWith("junit.jar")) {
junitJar = path;
break;
}
}
String jars = appJar + ps + junitJar;
// dump class list
ProcessBuilder pb = ProcessTools.createTestJvm(
"-XX:DumpLoadedClassList=" + classList,
"-cp", jars,
mainClass, testPackageName + "." + testClassName);
OutputAnalyzer output = TestCommon.executeAndLog(pb, "dumpClassList");
// create archive with the class list
CDSOptions opts = (new CDSOptions())
.addPrefix("-XX:ExtraSharedClassListFile=" + classList,
"-cp", jars,
"-Xlog:class+load,cds")
.setArchiveName(archiveName);
CDSTestUtils.createArchiveAndCheck(opts);
// run with archive
CDSOptions runOpts = (new CDSOptions())
.addPrefix("-cp", jars, "-Xlog:class+load,cds=debug")
.setArchiveName(archiveName)
.setUseVersion(false)
.addSuffix(mainClass, testPackageName + "." + testClassName);
output = CDSTestUtils.runWithArchive(runOpts);
output.shouldMatch(".class.load. test.java.lang.invoke.MethodHandlesPermuteArgumentsTest[$][$]Lambda[$].*/0x.*source:.*shared.*objects.*file")
.shouldHaveExitValue(0);
}
}

View 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.
*
*/
// this file is auto-generated by ./CDSMHTest_generate.sh. Do not edit manually.
/*
* @test
* @summary Run the MethodHandlesSpreadArgumentsTest.java test in static CDS archive mode.
* @requires vm.cds & vm.compMode != "Xcomp"
* @comment Some of the tests run excessively slowly with -Xcomp. The original
* tests aren't executed with -Xcomp in the CI pipeline, so let's exclude
* the generated tests from -Xcomp execution as well.
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
* /test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes
* @compile ../../../../../../jdk/java/lang/invoke/MethodHandlesTest.java
* ../../../../../../lib/jdk/test/lib/Utils.java
* ../../../../../../jdk/java/lang/invoke/MethodHandlesSpreadArgumentsTest.java
* ../../../../../../jdk/java/lang/invoke/remote/RemoteExample.java
* ../../../../../../jdk/java/lang/invoke/common/test/java/lang/invoke/lib/CodeCacheOverflowProcessor.java
* ../dynamicArchive/test-classes/TestMHApp.java
* @build sun.hotspot.WhiteBox
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
* @run junit/othervm/timeout=480 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. MethodHandlesSpreadArgumentsTest
*/
import org.junit.Test;
import java.io.File;
import jdk.test.lib.cds.CDSOptions;
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
public class MethodHandlesSpreadArgumentsTest {
@Test
public void test() throws Exception {
testImpl();
}
private static final String classDir = System.getProperty("test.classes");
private static final String mainClass = "TestMHApp";
private static final String javaClassPath = System.getProperty("java.class.path");
private static final String ps = System.getProperty("path.separator");
private static final String testPackageName = "test.java.lang.invoke";
private static final String testClassName = "MethodHandlesSpreadArgumentsTest";
static void testImpl() throws Exception {
String appJar = JarBuilder.build("MH", new File(classDir), null);
String classList = testClassName + ".list";
String archiveName = testClassName + ".jsa";
String[] classPaths = javaClassPath.split(File.pathSeparator);
String junitJar = null;
for (String path : classPaths) {
if (path.endsWith("junit.jar")) {
junitJar = path;
break;
}
}
String jars = appJar + ps + junitJar;
// dump class list
ProcessBuilder pb = ProcessTools.createTestJvm(
"-XX:DumpLoadedClassList=" + classList,
"-cp", jars,
mainClass, testPackageName + "." + testClassName);
OutputAnalyzer output = TestCommon.executeAndLog(pb, "dumpClassList");
// create archive with the class list
CDSOptions opts = (new CDSOptions())
.addPrefix("-XX:ExtraSharedClassListFile=" + classList,
"-cp", jars,
"-Xlog:class+load,cds")
.setArchiveName(archiveName);
CDSTestUtils.createArchiveAndCheck(opts);
// run with archive
CDSOptions runOpts = (new CDSOptions())
.addPrefix("-cp", jars, "-Xlog:class+load,cds=debug")
.setArchiveName(archiveName)
.setUseVersion(false)
.addSuffix(mainClass, testPackageName + "." + testClassName);
output = CDSTestUtils.runWithArchive(runOpts);
output.shouldMatch(".class.load. test.java.lang.invoke.MethodHandlesSpreadArgumentsTest[$][$]Lambda[$].*/0x.*source:.*shared.*objects.*file")
.shouldHaveExitValue(0);
}
}

View File

@ -0,0 +1,236 @@
/*
* 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.
*
*/
/*
* This class file has an incorrect constant pool entry #49 which results
* in an incorrect BSM.
* The correct entry should have a return type as follows instead of V:
* Ljava/lang/invoke/CallSite;"; // #49
*/
class WrongBSM {
0xCAFEBABE;
0; // minor version
59; // version
[] { // Constant Pool
; // first element is empty
Method #2 #3; // #1
class #4; // #2
NameAndType #5 #6; // #3
Utf8 "java/lang/Object"; // #4
Utf8 "<init>"; // #5
Utf8 "()V"; // #6
InvokeDynamic 0s #8; // #7
NameAndType #9 #10; // #8
Utf8 "run"; // #9
Utf8 "()Ljava/lang/Runnable;"; // #10
Method #12 #13; // #11
class #14; // #12
NameAndType #15 #16; // #13
Utf8 "WrongBSM"; // #14
Utf8 "doit"; // #15
Utf8 "(Ljava/lang/Runnable;)V"; // #16
InterfaceMethod #18 #19; // #17
class #20; // #18
NameAndType #9 #6; // #19
Utf8 "java/lang/Runnable"; // #20
Field #22 #23; // #21
class #24; // #22
NameAndType #25 #26; // #23
Utf8 "java/lang/System"; // #24
Utf8 "out"; // #25
Utf8 "Ljava/io/PrintStream;"; // #26
String #28; // #27
Utf8 "Hello from Lambda"; // #28
Method #30 #31; // #29
class #32; // #30
NameAndType #33 #34; // #31
Utf8 "java/io/PrintStream"; // #32
Utf8 "println"; // #33
Utf8 "(Ljava/lang/String;)V"; // #34
Utf8 "Code"; // #35
Utf8 "LineNumberTable"; // #36
Utf8 "main"; // #37
Utf8 "([Ljava/lang/String;)V"; // #38
Utf8 "lambda$main$0"; // #39
Utf8 "SourceFile"; // #40
Utf8 "WrongBSM.java"; // #41
Utf8 "BootstrapMethods"; // #42
MethodHandle 6b #44; // #43
Method #45 #46; // #44
class #47; // #45
NameAndType #48 #49; // #46
Utf8 "java/lang/invoke/LambdaMetafactory"; // #47
Utf8 "metafactory"; // #48
Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)V"; // #49
MethodType #6; // #50
MethodHandle 6b #52; // #51
Method #12 #53; // #52
NameAndType #39 #6; // #53
Utf8 "InnerClasses"; // #54
class #56; // #55
Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #56
class #58; // #57
Utf8 "java/lang/invoke/MethodHandles"; // #58
Utf8 "Lookup"; // #59
} // Constant Pool
0x0021; // access
#12;// this_cpx
#2;// super_cpx
[] { // Interfaces
} // Interfaces
[] { // Fields
} // Fields
[] { // Methods
{ // method
0x0001; // access
#5; // name_index
#6; // descriptor_index
[] { // Attributes
Attr(#35) { // Code
1; // max_stack
1; // max_locals
Bytes[]{
0x2AB70001B1;
}
[] { // Traps
} // end Traps
[] { // Attributes
Attr(#36) { // LineNumberTable
[] { // line_number_table
0 1;
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
}
;
{ // method
0x0009; // access
#37; // name_index
#38; // descriptor_index
[] { // Attributes
Attr(#35) { // Code
1; // max_stack
1; // max_locals
Bytes[]{
0xBA00070000B8000B;
0xB1;
}
[] { // Traps
} // end Traps
[] { // Attributes
Attr(#36) { // LineNumberTable
[] { // line_number_table
0 3;
8 6;
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
}
;
{ // method
0x0008; // access
#15; // name_index
#16; // descriptor_index
[] { // Attributes
Attr(#35) { // Code
1; // max_stack
1; // max_locals
Bytes[]{
0x2AB900110100B1;
}
[] { // Traps
} // end Traps
[] { // Attributes
Attr(#36) { // LineNumberTable
[] { // line_number_table
0 8;
6 9;
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
}
;
{ // method
0x100A; // access
#39; // name_index
#6; // descriptor_index
[] { // Attributes
Attr(#35) { // Code
2; // max_stack
0; // max_locals
Bytes[]{
0xB20015121BB6001D;
0xB1;
}
[] { // Traps
} // end Traps
[] { // Attributes
Attr(#36) { // LineNumberTable
[] { // line_number_table
0 4;
8 5;
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
}
} // Methods
[] { // Attributes
Attr(#40) { // SourceFile
#41;
} // end SourceFile
;
Attr(#42) { // BootstrapMethods
[] { // bootstrap_methods
{ // bootstrap_method
#43; // bootstrap_method_ref
[] { // bootstrap_arguments
#50;
#51;
#50;
} // bootstrap_arguments
} // bootstrap_method
}
} // end BootstrapMethods
;
Attr(#54) { // InnerClasses
[] { // classes
#55 #57 #59 25;
}
} // end InnerClasses
} // Attributes
} // end class WrongBSM