Skip to content

Commit 74ac77e

Browse files
committedOct 19, 2020
8247666: Support Lambda proxy classes in static CDS archive
Reviewed-by: iklam, mchung
1 parent e2e11d3 commit 74ac77e

38 files changed

+1960
-130
lines changed
 

‎make/hotspot/symbols/symbols-unix

+2-2
Original file line numberDiff line numberDiff line change
@@ -143,15 +143,15 @@ JVM_InternString
143143
JVM_Interrupt
144144
JVM_InvokeMethod
145145
JVM_IsArrayClass
146-
JVM_IsDynamicDumpingEnabled
147-
JVM_IsSharingEnabled
146+
JVM_IsCDSDumpingEnabled
148147
JVM_IsConstructorIx
149148
JVM_IsDumpingClassList
150149
JVM_IsHiddenClass
151150
JVM_IsInterface
152151
JVM_IsPrimitiveClass
153152
JVM_IsRecord
154153
JVM_IsSameClassPackage
154+
JVM_IsSharingEnabled
155155
JVM_IsSupportedJNIVersion
156156
JVM_IsThreadAlive
157157
JVM_IsVMGeneratedMethodIx

‎src/hotspot/share/classfile/classListParser.cpp

+181-7
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,14 @@
3232
#include "classfile/symbolTable.hpp"
3333
#include "classfile/systemDictionary.hpp"
3434
#include "classfile/systemDictionaryShared.hpp"
35+
#include "interpreter/bytecode.hpp"
36+
#include "interpreter/bytecodeStream.hpp"
37+
#include "interpreter/linkResolver.hpp"
3538
#include "logging/log.hpp"
3639
#include "logging/logTag.hpp"
3740
#include "memory/metaspaceShared.hpp"
3841
#include "memory/resourceArea.hpp"
42+
#include "oops/constantPool.hpp"
3943
#include "runtime/handles.inline.hpp"
4044
#include "runtime/java.hpp"
4145
#include "runtime/javaCalls.hpp"
@@ -65,6 +69,7 @@ ClassListParser::ClassListParser(const char* file) {
6569
}
6670
_line_no = 0;
6771
_interfaces = new (ResourceObj::C_HEAP, mtClass) GrowableArray<int>(10, mtClass);
72+
_indy_items = new (ResourceObj::C_HEAP, mtClass) GrowableArray<const char*>(9, mtClass);
6873
}
6974

7075
ClassListParser::~ClassListParser() {
@@ -127,6 +132,11 @@ bool ClassListParser::parse_one_line() {
127132
_interfaces->clear();
128133
_source = NULL;
129134
_interfaces_specified = false;
135+
_indy_items->clear();
136+
137+
if (_line[0] == '@') {
138+
return parse_at_tags();
139+
}
130140

131141
if ((_token = strchr(_line, ' ')) == NULL) {
132142
// No optional arguments are specified.
@@ -139,14 +149,14 @@ bool ClassListParser::parse_one_line() {
139149
while (*_token) {
140150
skip_whitespaces();
141151

142-
if (parse_int_option("id:", &_id)) {
152+
if (parse_uint_option("id:", &_id)) {
143153
continue;
144-
} else if (parse_int_option("super:", &_super)) {
154+
} else if (parse_uint_option("super:", &_super)) {
145155
check_already_loaded("Super class", _super);
146156
continue;
147157
} else if (skip_token("interfaces:")) {
148158
int i;
149-
while (try_parse_int(&i)) {
159+
while (try_parse_uint(&i)) {
150160
check_already_loaded("Interface", i);
151161
_interfaces->append(i);
152162
}
@@ -175,6 +185,41 @@ bool ClassListParser::parse_one_line() {
175185
return true;
176186
}
177187

188+
void ClassListParser::split_tokens_by_whitespace() {
189+
int start = 0;
190+
int end;
191+
bool done = false;
192+
while (!done) {
193+
while (_line[start] == ' ' || _line[start] == '\t') start++;
194+
end = start;
195+
while (_line[end] && _line[end] != ' ' && _line[end] != '\t') end++;
196+
if (_line[end] == '\0') {
197+
done = true;
198+
} else {
199+
_line[end] = '\0';
200+
}
201+
_indy_items->append(_line + start);
202+
start = ++end;
203+
}
204+
}
205+
206+
bool ClassListParser::parse_at_tags() {
207+
assert(_line[0] == '@', "must be");
208+
split_tokens_by_whitespace();
209+
if (strcmp(_indy_items->at(0), LAMBDA_PROXY_TAG) == 0) {
210+
if (_indy_items->length() < 3) {
211+
error("Line with @ tag has too few items \"%s\" line #%d", _line, _line_no);
212+
return false;
213+
}
214+
// set the class name
215+
_class_name = _indy_items->at(1);
216+
return true;
217+
} else {
218+
error("Invalid @ tag at the beginning of line \"%s\" line #%d", _line, _line_no);
219+
return false;
220+
}
221+
}
222+
178223
void ClassListParser::skip_whitespaces() {
179224
while (*_token == ' ' || *_token == '\t') {
180225
_token ++;
@@ -191,15 +236,19 @@ void ClassListParser::parse_int(int* value) {
191236
skip_whitespaces();
192237
if (sscanf(_token, "%i", value) == 1) {
193238
skip_non_whitespaces();
194-
if (*value < 0) {
195-
error("Error: negative integers not allowed (%d)", *value);
196-
}
197239
} else {
198240
error("Error: expected integer");
199241
}
200242
}
201243

202-
bool ClassListParser::try_parse_int(int* value) {
244+
void ClassListParser::parse_uint(int* value) {
245+
parse_int(value);
246+
if (*value < 0) {
247+
error("Error: negative integers not allowed (%d)", *value);
248+
}
249+
}
250+
251+
bool ClassListParser::try_parse_uint(int* value) {
203252
skip_whitespaces();
204253
if (sscanf(_token, "%i", value) == 1) {
205254
skip_non_whitespaces();
@@ -230,6 +279,18 @@ bool ClassListParser::parse_int_option(const char* option_name, int* value) {
230279
return false;
231280
}
232281

282+
bool ClassListParser::parse_uint_option(const char* option_name, int* value) {
283+
if (skip_token(option_name)) {
284+
if (*value != _unspecified) {
285+
error("%s specified twice", option_name);
286+
} else {
287+
parse_uint(value);
288+
return true;
289+
}
290+
}
291+
return false;
292+
}
293+
233294
void ClassListParser::print_specified_interfaces() {
234295
const int n = _interfaces->length();
235296
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
336397
return k;
337398
}
338399

400+
void ClassListParser::populate_cds_indy_info(const constantPoolHandle &pool, int cp_index, CDSIndyInfo* cii, TRAPS) {
401+
// Caller needs to allocate ResourceMark.
402+
int type_index = pool->bootstrap_name_and_type_ref_index_at(cp_index);
403+
int name_index = pool->name_ref_index_at(type_index);
404+
cii->add_item(pool->symbol_at(name_index)->as_C_string());
405+
int sig_index = pool->signature_ref_index_at(type_index);
406+
cii->add_item(pool->symbol_at(sig_index)->as_C_string());
407+
int argc = pool->bootstrap_argument_count_at(cp_index);
408+
if (argc > 0) {
409+
for (int arg_i = 0; arg_i < argc; arg_i++) {
410+
int arg = pool->bootstrap_argument_index_at(cp_index, arg_i);
411+
jbyte tag = pool->tag_at(arg).value();
412+
if (tag == JVM_CONSTANT_MethodType) {
413+
cii->add_item(pool->method_type_signature_at(arg)->as_C_string());
414+
} else if (tag == JVM_CONSTANT_MethodHandle) {
415+
cii->add_ref_kind(pool->method_handle_ref_kind_at(arg));
416+
int callee_index = pool->method_handle_klass_index_at(arg);
417+
Klass* callee = pool->klass_at(callee_index, THREAD);
418+
if (callee != NULL) {
419+
cii->add_item(callee->name()->as_C_string());
420+
}
421+
cii->add_item(pool->method_handle_name_ref_at(arg)->as_C_string());
422+
cii->add_item(pool->method_handle_signature_ref_at(arg)->as_C_string());
423+
} else {
424+
ShouldNotReachHere();
425+
}
426+
}
427+
}
428+
}
429+
430+
bool ClassListParser::is_matching_cp_entry(constantPoolHandle &pool, int cp_index, TRAPS) {
431+
ResourceMark rm(THREAD);
432+
CDSIndyInfo cii;
433+
populate_cds_indy_info(pool, cp_index, &cii, THREAD);
434+
GrowableArray<const char*>* items = cii.items();
435+
int indy_info_offset = 2;
436+
if (_indy_items->length() - indy_info_offset != items->length()) {
437+
return false;
438+
}
439+
for (int i = 0; i < items->length(); i++) {
440+
if (strcmp(_indy_items->at(i + indy_info_offset), items->at(i)) != 0) {
441+
return false;
442+
}
443+
}
444+
return true;
445+
}
446+
447+
void ClassListParser::resolve_indy(Symbol* class_name_symbol, TRAPS) {
448+
449+
Handle class_loader(THREAD, SystemDictionary::java_system_loader());
450+
Handle protection_domain;
451+
Klass* klass = SystemDictionary::resolve_or_fail(class_name_symbol, class_loader, protection_domain, true, THREAD); // FIXME should really be just a lookup
452+
if (klass != NULL && klass->is_instance_klass()) {
453+
InstanceKlass* ik = InstanceKlass::cast(klass);
454+
MetaspaceShared::try_link_class(ik, THREAD);
455+
assert(!HAS_PENDING_EXCEPTION, "unexpected exception");
456+
457+
ConstantPool* cp = ik->constants();
458+
ConstantPoolCache* cpcache = cp->cache();
459+
bool found = false;
460+
for (int cpcindex = 0; cpcindex < cpcache->length(); cpcindex ++) {
461+
int indy_index = ConstantPool::encode_invokedynamic_index(cpcindex);
462+
ConstantPoolCacheEntry* cpce = cpcache->entry_at(cpcindex);
463+
int pool_index = cpce->constant_pool_index();
464+
constantPoolHandle pool(THREAD, cp);
465+
if (pool->tag_at(pool_index).is_invoke_dynamic()) {
466+
BootstrapInfo bootstrap_specifier(pool, pool_index, indy_index);
467+
Handle bsm = bootstrap_specifier.resolve_bsm(THREAD);
468+
if (!SystemDictionaryShared::is_supported_invokedynamic(&bootstrap_specifier)) {
469+
tty->print_cr("is_supported_invokedynamic check failed for cp_index %d", pool_index);
470+
continue;
471+
}
472+
if (is_matching_cp_entry(pool, pool_index, THREAD)) {
473+
found = true;
474+
CallInfo info;
475+
bool is_done = bootstrap_specifier.resolve_previously_linked_invokedynamic(info, THREAD);
476+
if (!is_done) {
477+
// resolve it
478+
Handle recv;
479+
LinkResolver::resolve_invoke(info, recv, pool, indy_index, Bytecodes::_invokedynamic, THREAD);
480+
break;
481+
}
482+
cpce->set_dynamic_call(pool, info);
483+
if (HAS_PENDING_EXCEPTION) {
484+
ResourceMark rm(THREAD);
485+
tty->print("resolve_indy for class %s has", class_name_symbol->as_C_string());
486+
oop message = java_lang_Throwable::message(PENDING_EXCEPTION);
487+
if (message != NULL) {
488+
char* ex_msg = java_lang_String::as_utf8_string(message);
489+
tty->print_cr(" exception pending '%s %s'",
490+
PENDING_EXCEPTION->klass()->external_name(), ex_msg);
491+
} else {
492+
tty->print_cr(" exception pending %s ",
493+
PENDING_EXCEPTION->klass()->external_name());
494+
}
495+
exit(1);
496+
}
497+
}
498+
}
499+
}
500+
if (!found) {
501+
ResourceMark rm(THREAD);
502+
log_warning(cds)("No invoke dynamic constant pool entry can be found for class %s. The classlist is probably out-of-date.",
503+
class_name_symbol->as_C_string());
504+
}
505+
}
506+
}
507+
339508
Klass* ClassListParser::load_current_class(TRAPS) {
340509
TempNewSymbol class_name_symbol = SymbolTable::new_symbol(_class_name);
341510

511+
if (_indy_items->length() > 0) {
512+
resolve_indy(class_name_symbol, CHECK_NULL);
513+
return NULL;
514+
}
515+
342516
Klass* klass = NULL;
343517
if (!is_loading_from_source()) {
344518
// Load classes for the boot/platform/app loaders only.

‎src/hotspot/share/classfile/classListParser.hpp

+43-1
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,43 @@
3030
#include "utilities/growableArray.hpp"
3131
#include "utilities/hashtable.inline.hpp"
3232

33+
#define LAMBDA_PROXY_TAG "@lambda-proxy:"
34+
3335
class ID2KlassTable : public KVHashtable<int, InstanceKlass*, mtInternal> {
3436
public:
3537
ID2KlassTable() : KVHashtable<int, InstanceKlass*, mtInternal>(1987) {}
3638
};
3739

40+
class CDSIndyInfo {
41+
GrowableArray<const char*>* _items;
42+
public:
43+
CDSIndyInfo() : _items(NULL) {}
44+
void add_item(const char* item) {
45+
if (_items == NULL) {
46+
_items = new GrowableArray<const char*>(9);
47+
}
48+
assert(_items != NULL, "sanity");
49+
_items->append(item);
50+
}
51+
void add_ref_kind(int ref_kind) {
52+
switch (ref_kind) {
53+
case JVM_REF_getField : _items->append("REF_getField"); break;
54+
case JVM_REF_getStatic : _items->append("REF_getStatic"); break;
55+
case JVM_REF_putField : _items->append("REF_putField"); break;
56+
case JVM_REF_putStatic : _items->append("REF_putStatic"); break;
57+
case JVM_REF_invokeVirtual : _items->append("REF_invokeVirtual"); break;
58+
case JVM_REF_invokeStatic : _items->append("REF_invokeStatic"); break;
59+
case JVM_REF_invokeSpecial : _items->append("REF_invokeSpecial"); break;
60+
case JVM_REF_newInvokeSpecial : _items->append("REF_newInvokeSpecial"); break;
61+
case JVM_REF_invokeInterface : _items->append("REF_invokeInterface"); break;
62+
default : ShouldNotReachHere();
63+
}
64+
}
65+
GrowableArray<const char*>* items() {
66+
return _items;
67+
}
68+
};
69+
3870
class ClassListParser : public StackObj {
3971
enum {
4072
_unspecified = -999,
@@ -61,20 +93,25 @@ class ClassListParser : public StackObj {
6193
int _line_len; // Original length of the input line.
6294
int _line_no; // Line number for current line being parsed
6395
const char* _class_name;
96+
GrowableArray<const char*>* _indy_items; // items related to invoke dynamic for archiving lambda proxy classes
6497
int _id;
6598
int _super;
6699
GrowableArray<int>* _interfaces;
67100
bool _interfaces_specified;
68101
const char* _source;
69102

70103
bool parse_int_option(const char* option_name, int* value);
104+
bool parse_uint_option(const char* option_name, int* value);
71105
InstanceKlass* load_class_from_source(Symbol* class_name, TRAPS);
72106
ID2KlassTable *table() {
73107
return &_id2klass_table;
74108
}
75109
InstanceKlass* lookup_class_by_id(int id);
76110
void print_specified_interfaces();
77111
void print_actual_interfaces(InstanceKlass *ik);
112+
bool is_matching_cp_entry(constantPoolHandle &pool, int cp_index, TRAPS);
113+
114+
void resolve_indy(Symbol* class_name_symbol, TRAPS);
78115
public:
79116
ClassListParser(const char* file);
80117
~ClassListParser();
@@ -83,10 +120,13 @@ class ClassListParser : public StackObj {
83120
return _instance;
84121
}
85122
bool parse_one_line();
123+
void split_tokens_by_whitespace();
124+
bool parse_at_tags();
86125
char* _token;
87126
void error(const char* msg, ...);
88127
void parse_int(int* value);
89-
bool try_parse_int(int* value);
128+
void parse_uint(int* value);
129+
bool try_parse_uint(int* value);
90130
bool skip_token(const char* option_name);
91131
void skip_whitespaces();
92132
void skip_non_whitespaces();
@@ -126,5 +166,7 @@ class ClassListParser : public StackObj {
126166
// (in this->load_current_class()).
127167
InstanceKlass* lookup_super_for_current_class(Symbol* super_name);
128168
InstanceKlass* lookup_interface_for_current_class(Symbol* interface_name);
169+
170+
static void populate_cds_indy_info(const constantPoolHandle &pool, int cp_index, CDSIndyInfo* cii, TRAPS);
129171
};
130172
#endif // SHARE_CLASSFILE_CLASSLISTPARSER_HPP

0 commit comments

Comments
 (0)
Please sign in to comment.