Skip to content

Commit e7b6f48

Browse files
committed
8265602: -XX:DumpLoadedClassList should support custom loaders
Reviewed-by: ccheung, minqi
1 parent ea02dad commit e7b6f48

File tree

14 files changed

+510
-144
lines changed

14 files changed

+510
-144
lines changed

src/hotspot/share/cds/archiveBuilder.cpp

Lines changed: 58 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,6 @@ ArchiveBuilder::ArchiveBuilder() :
161161
_rw_src_objs(),
162162
_ro_src_objs(),
163163
_src_obj_table(INITIAL_TABLE_SIZE, MAX_TABLE_SIZE),
164-
_num_instance_klasses(0),
165-
_num_obj_array_klasses(0),
166-
_num_type_array_klasses(0),
167164
_total_closed_heap_region_size(0),
168165
_total_open_heap_region_size(0),
169166
_estimated_metaspaceobj_bytes(0),
@@ -222,14 +219,6 @@ bool ArchiveBuilder::gather_klass_and_symbol(MetaspaceClosure::Ref* ref, bool re
222219
assert(klass->is_klass(), "must be");
223220
if (!is_excluded(klass)) {
224221
_klasses->append(klass);
225-
if (klass->is_instance_klass()) {
226-
_num_instance_klasses ++;
227-
} else if (klass->is_objArray_klass()) {
228-
_num_obj_array_klasses ++;
229-
} else {
230-
assert(klass->is_typeArray_klass(), "sanity");
231-
_num_type_array_klasses ++;
232-
}
233222
}
234223
// See RunTimeClassInfo::get_for()
235224
_estimated_metaspaceobj_bytes += align_up(BytesPerWord, SharedSpaceObjectAlignment);
@@ -258,12 +247,6 @@ void ArchiveBuilder::gather_klasses_and_symbols() {
258247
#endif
259248
doit.finish();
260249

261-
log_info(cds)("Number of classes %d", _num_instance_klasses + _num_obj_array_klasses + _num_type_array_klasses);
262-
log_info(cds)(" instance classes = %5d", _num_instance_klasses);
263-
log_info(cds)(" obj array classes = %5d", _num_obj_array_klasses);
264-
log_info(cds)(" type array classes = %5d", _num_type_array_klasses);
265-
log_info(cds)(" symbols = %5d", _symbols->length());
266-
267250
if (DumpSharedSpaces) {
268251
// To ensure deterministic contents in the static archive, we need to ensure that
269252
// we iterate the MetaspaceObjs in a deterministic order. It doesn't matter where
@@ -731,31 +714,85 @@ void ArchiveBuilder::relocate_vm_classes() {
731714
}
732715

733716
void ArchiveBuilder::make_klasses_shareable() {
717+
int num_instance_klasses = 0;
718+
int num_boot_klasses = 0;
719+
int num_platform_klasses = 0;
720+
int num_app_klasses = 0;
721+
int num_hidden_klasses = 0;
722+
int num_unlinked_klasses = 0;
723+
int num_unregistered_klasses = 0;
724+
int num_obj_array_klasses = 0;
725+
int num_type_array_klasses = 0;
726+
734727
for (int i = 0; i < klasses()->length(); i++) {
728+
const char* type;
729+
const char* unlinked = "";
730+
const char* hidden = "";
735731
Klass* k = klasses()->at(i);
736732
k->remove_java_mirror();
737733
if (k->is_objArray_klass()) {
738734
// InstanceKlass and TypeArrayKlass will in turn call remove_unshareable_info
739735
// on their array classes.
736+
num_obj_array_klasses ++;
737+
type = "array";
740738
} else if (k->is_typeArray_klass()) {
739+
num_type_array_klasses ++;
740+
type = "array";
741741
k->remove_unshareable_info();
742742
} else {
743743
assert(k->is_instance_klass(), " must be");
744+
num_instance_klasses ++;
744745
InstanceKlass* ik = InstanceKlass::cast(k);
745746
if (DynamicDumpSharedSpaces) {
746747
// For static dump, class loader type are already set.
747748
ik->assign_class_loader_type();
748749
}
750+
if (ik->is_shared_boot_class()) {
751+
type = "boot";
752+
num_boot_klasses ++;
753+
} else if (ik->is_shared_platform_class()) {
754+
type = "plat";
755+
num_platform_klasses ++;
756+
} else if (ik->is_shared_app_class()) {
757+
type = "app";
758+
num_app_klasses ++;
759+
} else {
760+
assert(ik->is_shared_unregistered_class(), "must be");
761+
type = "unreg";
762+
num_unregistered_klasses ++;
763+
}
764+
765+
if (!ik->is_linked()) {
766+
num_unlinked_klasses ++;
767+
unlinked = " ** unlinked";
768+
}
769+
770+
if (ik->is_hidden()) {
771+
num_hidden_klasses ++;
772+
hidden = " ** hidden";
773+
}
749774

750775
MetaspaceShared::rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread::current(), ik);
751776
ik->remove_unshareable_info();
777+
}
752778

753-
if (log_is_enabled(Debug, cds, class)) {
754-
ResourceMark rm;
755-
log_debug(cds, class)("klasses[%4d] = " PTR_FORMAT " %s", i, p2i(to_requested(ik)), ik->external_name());
756-
}
779+
if (log_is_enabled(Debug, cds, class)) {
780+
ResourceMark rm;
781+
log_debug(cds, class)("klasses[%5d] = " PTR_FORMAT " %-5s %s%s%s", i, p2i(to_requested(k)), type, k->external_name(), hidden, unlinked);
757782
}
758783
}
784+
785+
log_info(cds)("Number of classes %d", num_instance_klasses + num_obj_array_klasses + num_type_array_klasses);
786+
log_info(cds)(" instance classes = %5d", num_instance_klasses);
787+
log_info(cds)(" boot = %5d", num_boot_klasses);
788+
log_info(cds)(" app = %5d", num_app_klasses);
789+
log_info(cds)(" platform = %5d", num_platform_klasses);
790+
log_info(cds)(" unregistered = %5d", num_unregistered_klasses);
791+
log_info(cds)(" (hidden) = %5d", num_hidden_klasses);
792+
log_info(cds)(" (unlinked) = %5d", num_unlinked_klasses);
793+
log_info(cds)(" obj array classes = %5d", num_obj_array_klasses);
794+
log_info(cds)(" type array classes = %5d", num_type_array_klasses);
795+
log_info(cds)(" symbols = %5d", _symbols->length());
759796
}
760797

761798
uintx ArchiveBuilder::buffer_to_offset(address p) const {

src/hotspot/share/cds/archiveBuilder.hpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,6 @@ class ArchiveBuilder : public StackObj {
205205
GrowableArray<SpecialRefInfo>* _special_refs;
206206

207207
// statistics
208-
int _num_instance_klasses;
209-
int _num_obj_array_klasses;
210-
int _num_type_array_klasses;
211208
DumpAllocStats _alloc_stats;
212209
size_t _total_closed_heap_region_size;
213210
size_t _total_open_heap_region_size;

src/hotspot/share/cds/archiveUtils.cpp

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -330,23 +330,24 @@ void ReadClosure::do_region(u_char* start, size_t size) {
330330
}
331331
}
332332

333-
fileStream* ClassListWriter::_classlist_file = NULL;
334-
335333
void ArchiveUtils::log_to_classlist(BootstrapInfo* bootstrap_specifier, TRAPS) {
336334
if (ClassListWriter::is_enabled()) {
337335
if (SystemDictionaryShared::is_supported_invokedynamic(bootstrap_specifier)) {
338-
ResourceMark rm(THREAD);
339336
const constantPoolHandle& pool = bootstrap_specifier->pool();
340-
int pool_index = bootstrap_specifier->bss_index();
341-
ClassListWriter w;
342-
w.stream()->print("%s %s", LAMBDA_PROXY_TAG, pool->pool_holder()->name()->as_C_string());
343-
CDSIndyInfo cii;
344-
ClassListParser::populate_cds_indy_info(pool, pool_index, &cii, CHECK);
345-
GrowableArray<const char*>* indy_items = cii.items();
346-
for (int i = 0; i < indy_items->length(); i++) {
347-
w.stream()->print(" %s", indy_items->at(i));
337+
if (SystemDictionaryShared::is_builtin_loader(pool->pool_holder()->class_loader_data())) {
338+
// Currently lambda proxy classes are supported only for the built-in loaders.
339+
ResourceMark rm(THREAD);
340+
int pool_index = bootstrap_specifier->bss_index();
341+
ClassListWriter w;
342+
w.stream()->print("%s %s", LAMBDA_PROXY_TAG, pool->pool_holder()->name()->as_C_string());
343+
CDSIndyInfo cii;
344+
ClassListParser::populate_cds_indy_info(pool, pool_index, &cii, CHECK);
345+
GrowableArray<const char*>* indy_items = cii.items();
346+
for (int i = 0; i < indy_items->length(); i++) {
347+
w.stream()->print(" %s", indy_items->at(i));
348+
}
349+
w.stream()->cr();
348350
}
349-
w.stream()->cr();
350351
}
351352
}
352353
}
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
/*
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*
23+
*/
24+
25+
#include "precompiled.hpp"
26+
#include "cds/classListWriter.hpp"
27+
#include "classfile/classFileStream.hpp"
28+
#include "classfile/classLoader.hpp"
29+
#include "classfile/classLoaderData.hpp"
30+
#include "classfile/moduleEntry.hpp"
31+
#include "classfile/systemDictionaryShared.hpp"
32+
#include "memory/resourceArea.hpp"
33+
#include "oops/instanceKlass.hpp"
34+
#include "runtime/mutexLocker.hpp"
35+
36+
fileStream* ClassListWriter::_classlist_file = NULL;
37+
38+
void ClassListWriter::init() {
39+
// For -XX:DumpLoadedClassList=<file> option
40+
if (DumpLoadedClassList != NULL) {
41+
const char* list_name = make_log_name(DumpLoadedClassList, NULL);
42+
_classlist_file = new(ResourceObj::C_HEAP, mtInternal)
43+
fileStream(list_name);
44+
_classlist_file->print_cr("# NOTE: Do not modify this file.");
45+
_classlist_file->print_cr("#");
46+
_classlist_file->print_cr("# This file is generated via the -XX:DumpLoadedClassList=<class_list_file> option");
47+
_classlist_file->print_cr("# and is used at CDS archive dump time (see -Xshare:dump).");
48+
_classlist_file->print_cr("#");
49+
FREE_C_HEAP_ARRAY(char, list_name);
50+
}
51+
}
52+
53+
void ClassListWriter::write(const InstanceKlass* k, const ClassFileStream* cfs) {
54+
assert(is_enabled(), "must be");
55+
56+
if (!ClassLoader::has_jrt_entry()) {
57+
warning("DumpLoadedClassList and CDS are not supported in exploded build");
58+
DumpLoadedClassList = NULL;
59+
return;
60+
}
61+
62+
ClassListWriter w;
63+
write_to_stream(k, w.stream(), cfs);
64+
}
65+
66+
class ClassListWriter::IDTable : public ResourceHashtable<
67+
const InstanceKlass*, int,
68+
15889, // prime number
69+
ResourceObj::C_HEAP> {};
70+
71+
ClassListWriter::IDTable* ClassListWriter::_id_table = NULL;
72+
int ClassListWriter::_total_ids = 0;
73+
74+
int ClassListWriter::get_id(const InstanceKlass* k) {
75+
assert_locked();
76+
if (_id_table == NULL) {
77+
_id_table = new (ResourceObj::C_HEAP, mtClass)IDTable();
78+
}
79+
bool created;
80+
int* v = _id_table->put_if_absent(k, &created);
81+
if (created) {
82+
*v = _total_ids++;
83+
}
84+
return *v;
85+
}
86+
87+
bool ClassListWriter::has_id(const InstanceKlass* k) {
88+
assert_locked();
89+
if (_id_table != NULL) {
90+
return _id_table->get(k) != NULL;
91+
} else {
92+
return false;
93+
}
94+
}
95+
96+
void ClassListWriter::handle_class_unloading(const InstanceKlass* klass) {
97+
assert_locked();
98+
if (_id_table != NULL) {
99+
_id_table->remove(klass);
100+
}
101+
}
102+
103+
void ClassListWriter::write_to_stream(const InstanceKlass* k, outputStream* stream, const ClassFileStream* cfs) {
104+
assert_locked();
105+
ClassLoaderData* loader_data = k->class_loader_data();
106+
107+
if (!SystemDictionaryShared::is_builtin_loader(loader_data)) {
108+
if (cfs == NULL || strncmp(cfs->source(), "file:", 5) != 0) {
109+
return;
110+
}
111+
if (!SystemDictionaryShared::add_unregistered_class(Thread::current(), (InstanceKlass*)k)) {
112+
return;
113+
}
114+
}
115+
116+
117+
{
118+
InstanceKlass* super = k->java_super();
119+
if (super != NULL && !has_id(super)) {
120+
return;
121+
}
122+
123+
Array<InstanceKlass*>* interfaces = k->local_interfaces();
124+
int len = interfaces->length();
125+
for (int i = 0; i < len; i++) {
126+
InstanceKlass* intf = interfaces->at(i);
127+
if (!has_id(intf)) {
128+
return;
129+
}
130+
}
131+
}
132+
133+
if (k->is_hidden()) {
134+
return;
135+
}
136+
137+
if (k->module()->is_patched()) {
138+
return;
139+
}
140+
141+
ResourceMark rm;
142+
stream->print("%s id: %d", k->name()->as_C_string(), get_id(k));
143+
if (!SystemDictionaryShared::is_builtin_loader(loader_data)) {
144+
InstanceKlass* super = k->java_super();
145+
assert(super != NULL, "must be");
146+
stream->print(" super: %d", get_id(super));
147+
148+
Array<InstanceKlass*>* interfaces = k->local_interfaces();
149+
int len = interfaces->length();
150+
if (len > 0) {
151+
stream->print(" interfaces:");
152+
for (int i = 0; i < len; i++) {
153+
InstanceKlass* intf = interfaces->at(i);
154+
stream->print(" %d", get_id(intf));
155+
}
156+
}
157+
158+
#ifdef _WINDOWS
159+
// "file:/C:/dir/foo.jar" -> "C:/dir/foo.jar"
160+
stream->print(" source: %s", cfs->source() + 6);
161+
#else
162+
// "file:/dir/foo.jar" -> "/dir/foo.jar"
163+
stream->print(" source: %s", cfs->source() + 5);
164+
#endif
165+
}
166+
167+
stream->cr();
168+
stream->flush();
169+
}
170+
171+
void ClassListWriter::delete_classlist() {
172+
if (_classlist_file != NULL) {
173+
delete _classlist_file;
174+
}
175+
}

0 commit comments

Comments
 (0)