mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
8247666: Support Lambda proxy classes in static CDS archive
Reviewed-by: iklam, mchung
This commit is contained in:
parent
e2e11d3449
commit
74ac77e2b1
38 changed files with 1960 additions and 130 deletions
|
@ -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.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue