mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 12:09:14 +00:00
8247666: Support Lambda proxy classes in static CDS archive
Reviewed-by: iklam, mchung
This commit is contained in:
parent
e2e11d3449
commit
74ac77e2b1
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
83
src/hotspot/share/classfile/classListWriter.hpp
Normal file
83
src/hotspot/share/classfile/classListWriter.hpp
Normal 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
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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 \
|
||||
|
||||
49
test/hotspot/jtreg/runtime/cds/appcds/BadBSM.java
Normal file
49
test/hotspot/jtreg/runtime/cds/appcds/BadBSM.java
Normal 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");
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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)");
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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");
|
||||
});
|
||||
|
||||
@ -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"
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
236
test/hotspot/jtreg/runtime/cds/appcds/test-classes/WrongBSM.jcod
Normal file
236
test/hotspot/jtreg/runtime/cds/appcds/test-classes/WrongBSM.jcod
Normal 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
|
||||
Loading…
x
Reference in New Issue
Block a user