Skip to content

Commit 84e985d

Browse files
committed
8253920: Share method trampolines in CDS dynamic archive
Reviewed-by: redestad, minqi, iklam
1 parent 7d41a54 commit 84e985d

File tree

8 files changed

+135
-102
lines changed

8 files changed

+135
-102
lines changed

src/hotspot/share/classfile/systemDictionaryShared.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,19 +1179,24 @@ InstanceKlass* SystemDictionaryShared::acquire_class_for_current_thread(
11791179
return shared_klass;
11801180
}
11811181

1182-
static ResourceHashtable<
1182+
class LoadedUnregisteredClassesTable : public ResourceHashtable<
11831183
Symbol*, bool,
11841184
primitive_hash<Symbol*>,
11851185
primitive_equals<Symbol*>,
11861186
6661, // prime number
1187-
ResourceObj::C_HEAP> _loaded_unregistered_classes;
1187+
ResourceObj::C_HEAP> {};
1188+
1189+
static LoadedUnregisteredClassesTable* _loaded_unregistered_classes = NULL;
11881190

11891191
bool SystemDictionaryShared::add_unregistered_class(InstanceKlass* k, TRAPS) {
11901192
// We don't allow duplicated unregistered classes of the same name.
11911193
assert(DumpSharedSpaces, "only when dumping");
11921194
Symbol* name = k->name();
1195+
if (_loaded_unregistered_classes == NULL) {
1196+
_loaded_unregistered_classes = new (ResourceObj::C_HEAP, mtClass)LoadedUnregisteredClassesTable();
1197+
}
11931198
bool created = false;
1194-
_loaded_unregistered_classes.put_if_absent(name, true, &created);
1199+
_loaded_unregistered_classes->put_if_absent(name, true, &created);
11951200
if (created) {
11961201
MutexLocker mu_r(THREAD, Compile_lock); // add_to_hierarchy asserts this.
11971202
SystemDictionary::add_to_hierarchy(k, CHECK_false);

src/hotspot/share/memory/archiveBuilder.cpp

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,35 @@
3838
#include "oops/instanceKlass.hpp"
3939
#include "oops/objArrayKlass.hpp"
4040
#include "oops/oopHandle.inline.hpp"
41+
#include "runtime/sharedRuntime.hpp"
4142
#include "utilities/align.hpp"
4243
#include "utilities/bitMap.inline.hpp"
4344
#include "utilities/hashtable.inline.hpp"
4445

4546
ArchiveBuilder* ArchiveBuilder::_singleton = NULL;
4647
intx ArchiveBuilder::_buffer_to_target_delta = 0;
4748

49+
class AdapterHandlerEntry;
50+
51+
class MethodTrampolineInfo {
52+
address _c2i_entry_trampoline;
53+
AdapterHandlerEntry** _adapter_trampoline;
54+
public:
55+
address c2i_entry_trampoline() { return _c2i_entry_trampoline; }
56+
AdapterHandlerEntry** adapter_trampoline() { return _adapter_trampoline; }
57+
void set_c2i_entry_trampoline(address addr) { _c2i_entry_trampoline = addr; }
58+
void set_adapter_trampoline(AdapterHandlerEntry** entry) { _adapter_trampoline = entry; }
59+
};
60+
61+
class AdapterToTrampoline : public ResourceHashtable<
62+
AdapterHandlerEntry*, MethodTrampolineInfo,
63+
primitive_hash<AdapterHandlerEntry*>,
64+
primitive_equals<AdapterHandlerEntry*>,
65+
941, // prime number
66+
ResourceObj::C_HEAP> {};
67+
68+
static AdapterToTrampoline* _adapter_to_trampoline = NULL;
69+
4870
ArchiveBuilder::OtherROAllocMark::~OtherROAllocMark() {
4971
char* newtop = ArchiveBuilder::singleton()->_ro_region->top();
5072
ArchiveBuilder::alloc_stats()->record_other_type(int(newtop - _oldtop), true);
@@ -259,6 +281,8 @@ void ArchiveBuilder::gather_klasses_and_symbols() {
259281
// DynamicArchiveBuilder::sort_methods()).
260282
sort_symbols_and_fix_hash();
261283
sort_klasses();
284+
allocate_method_trampoline_info();
285+
allocate_method_trampolines();
262286
}
263287
}
264288

@@ -798,3 +822,89 @@ void ArchiveBuilder::clean_up_src_obj_table() {
798822
SrcObjTableCleaner cleaner;
799823
_src_obj_table.iterate(&cleaner);
800824
}
825+
826+
void ArchiveBuilder::allocate_method_trampolines_for(InstanceKlass* ik) {
827+
if (ik->methods() != NULL) {
828+
for (int j = 0; j < ik->methods()->length(); j++) {
829+
// Walk the methods in a deterministic order so that the trampolines are
830+
// created in a deterministic order.
831+
Method* m = ik->methods()->at(j);
832+
AdapterHandlerEntry* ent = m->adapter(); // different methods can share the same AdapterHandlerEntry
833+
MethodTrampolineInfo* info = _adapter_to_trampoline->get(ent);
834+
if (info->c2i_entry_trampoline() == NULL) {
835+
info->set_c2i_entry_trampoline(
836+
(address)MetaspaceShared::misc_code_space_alloc(SharedRuntime::trampoline_size()));
837+
info->set_adapter_trampoline(
838+
(AdapterHandlerEntry**)MetaspaceShared::misc_code_space_alloc(sizeof(AdapterHandlerEntry*)));
839+
}
840+
}
841+
}
842+
}
843+
844+
void ArchiveBuilder::allocate_method_trampolines() {
845+
for (int i = 0; i < _klasses->length(); i++) {
846+
Klass* k = _klasses->at(i);
847+
if (k->is_instance_klass()) {
848+
InstanceKlass* ik = InstanceKlass::cast(k);
849+
allocate_method_trampolines_for(ik);
850+
}
851+
}
852+
}
853+
854+
// Allocate MethodTrampolineInfo for all Methods that will be archived. Also
855+
// return the total number of bytes needed by the method trampolines in the MC
856+
// region.
857+
size_t ArchiveBuilder::allocate_method_trampoline_info() {
858+
size_t total = 0;
859+
size_t each_method_bytes =
860+
align_up(SharedRuntime::trampoline_size(), BytesPerWord) +
861+
align_up(sizeof(AdapterHandlerEntry*), BytesPerWord);
862+
863+
if (_adapter_to_trampoline == NULL) {
864+
_adapter_to_trampoline = new (ResourceObj::C_HEAP, mtClass)AdapterToTrampoline();
865+
}
866+
int count = 0;
867+
for (int i = 0; i < _klasses->length(); i++) {
868+
Klass* k = _klasses->at(i);
869+
if (k->is_instance_klass()) {
870+
InstanceKlass* ik = InstanceKlass::cast(k);
871+
if (ik->methods() != NULL) {
872+
for (int j = 0; j < ik->methods()->length(); j++) {
873+
Method* m = ik->methods()->at(j);
874+
AdapterHandlerEntry* ent = m->adapter(); // different methods can share the same AdapterHandlerEntry
875+
bool is_created = false;
876+
MethodTrampolineInfo* info = _adapter_to_trampoline->put_if_absent(ent, &is_created);
877+
if (is_created) {
878+
count++;
879+
}
880+
}
881+
}
882+
}
883+
}
884+
if (count == 0) {
885+
// We have nothing to archive, but let's avoid having an empty region.
886+
total = SharedRuntime::trampoline_size();
887+
} else {
888+
total = count * each_method_bytes;
889+
}
890+
return align_up(total, SharedSpaceObjectAlignment);
891+
}
892+
893+
void ArchiveBuilder::update_method_trampolines() {
894+
for (int i = 0; i < klasses()->length(); i++) {
895+
Klass* k = klasses()->at(i);
896+
if (k->is_instance_klass()) {
897+
InstanceKlass* ik = InstanceKlass::cast(k);
898+
Array<Method*>* methods = ik->methods();
899+
for (int j = 0; j < methods->length(); j++) {
900+
Method* m = methods->at(j);
901+
AdapterHandlerEntry* ent = m->adapter();
902+
MethodTrampolineInfo* info = _adapter_to_trampoline->get(ent);
903+
// m is the "copy" of the original Method, but its adapter() field is still valid because
904+
// we haven't called make_klasses_shareable() yet.
905+
m->set_from_compiled_entry(info->c2i_entry_trampoline());
906+
m->set_adapter_trampoline(info->adapter_trampoline());
907+
}
908+
}
909+
}
910+
}

src/hotspot/share/memory/archiveBuilder.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,13 @@ class ArchiveBuilder : public StackObj {
279279

280280
void print_stats(int ro_all, int rw_all, int mc_all);
281281
static intx _buffer_to_target_delta;
282+
283+
// Method trampolines related functions
284+
void allocate_method_trampolines();
285+
void allocate_method_trampolines_for(InstanceKlass* ik);
286+
size_t allocate_method_trampoline_info();
287+
void update_method_trampolines();
288+
282289
};
283290

284291
#endif // SHARE_MEMORY_ARCHIVEBUILDER_HPP

src/hotspot/share/memory/dynamicArchive.cpp

Lines changed: 3 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,10 @@ class DynamicArchiveBuilder : public ArchiveBuilder {
9393
size_t _estimated_trampoline_bytes; // method entry trampolines
9494

9595
size_t estimate_archive_size();
96-
size_t estimate_trampoline_size();
9796
size_t estimate_class_file_size();
9897
address reserve_space_and_init_buffer_to_target_delta();
9998
void init_header(address addr);
10099
void release_header();
101-
void make_trampolines();
102100
void sort_methods();
103101
void sort_methods(InstanceKlass* ik) const;
104102
void remark_pointers_for_instance_klass(InstanceKlass* k, bool should_mark) const;
@@ -116,12 +114,6 @@ class DynamicArchiveBuilder : public ArchiveBuilder {
116114
_num_dump_regions_used = 1;
117115
}
118116

119-
void reserve_buffers_for_trampolines() {
120-
size_t n = _estimated_trampoline_bytes;
121-
assert(n >= SharedRuntime::trampoline_size(), "dont want to be empty");
122-
MetaspaceShared::misc_code_space_alloc(n);
123-
}
124-
125117
public:
126118
DynamicArchiveBuilder() : ArchiveBuilder(MetaspaceShared::misc_code_dump_space(),
127119
MetaspaceShared::read_write_dump_space(),
@@ -184,7 +176,7 @@ class DynamicArchiveBuilder : public ArchiveBuilder {
184176
CHeapBitMap ptrmap;
185177
ArchivePtrMarker::initialize(&ptrmap, (address*)reserved_bottom, (address*)current_dump_space()->top());
186178

187-
reserve_buffers_for_trampolines();
179+
allocate_method_trampolines();
188180
verify_estimate_size(_estimated_trampoline_bytes, "Trampolines");
189181

190182
gather_source_objs();
@@ -221,7 +213,7 @@ class DynamicArchiveBuilder : public ArchiveBuilder {
221213

222214
verify_estimate_size(_estimated_hashtable_bytes, "Hashtables");
223215

224-
make_trampolines();
216+
update_method_trampolines();
225217
sort_methods();
226218

227219
log_info(cds)("Make classes shareable");
@@ -254,7 +246,7 @@ size_t DynamicArchiveBuilder::estimate_archive_size() {
254246
size_t dictionary_est = SystemDictionaryShared::estimate_size_for_archive();
255247
_estimated_hashtable_bytes = symbol_table_est + dictionary_est;
256248

257-
_estimated_trampoline_bytes = estimate_trampoline_size();
249+
_estimated_trampoline_bytes = allocate_method_trampoline_info();
258250

259251
size_t total = 0;
260252

@@ -337,54 +329,6 @@ void DynamicArchiveBuilder::release_header() {
337329
_header = NULL;
338330
}
339331

340-
size_t DynamicArchiveBuilder::estimate_trampoline_size() {
341-
size_t total = 0;
342-
size_t each_method_bytes =
343-
align_up(SharedRuntime::trampoline_size(), BytesPerWord) +
344-
align_up(sizeof(AdapterHandlerEntry*), BytesPerWord);
345-
346-
for (int i = 0; i < klasses()->length(); i++) {
347-
Klass* k = klasses()->at(i);
348-
if (k->is_instance_klass()) {
349-
Array<Method*>* methods = InstanceKlass::cast(k)->methods();
350-
total += each_method_bytes * methods->length();
351-
}
352-
}
353-
if (total == 0) {
354-
// We have nothing to archive, but let's avoid having an empty region.
355-
total = SharedRuntime::trampoline_size();
356-
}
357-
return align_up(total, SharedSpaceObjectAlignment);
358-
}
359-
360-
void DynamicArchiveBuilder::make_trampolines() {
361-
DumpRegion* mc_space = MetaspaceShared::misc_code_dump_space();
362-
char* p = mc_space->base();
363-
for (int i = 0; i < klasses()->length(); i++) {
364-
Klass* k = klasses()->at(i);
365-
if (!k->is_instance_klass()) {
366-
continue;
367-
}
368-
InstanceKlass* ik = InstanceKlass::cast(k);
369-
Array<Method*>* methods = ik->methods();
370-
for (int j = 0; j < methods->length(); j++) {
371-
Method* m = methods->at(j);
372-
address c2i_entry_trampoline = (address)p;
373-
p += SharedRuntime::trampoline_size();
374-
assert(p >= mc_space->base() && p <= mc_space->top(), "must be");
375-
m->set_from_compiled_entry(to_target(c2i_entry_trampoline));
376-
377-
AdapterHandlerEntry** adapter_trampoline =(AdapterHandlerEntry**)p;
378-
p += sizeof(AdapterHandlerEntry*);
379-
assert(p >= mc_space->base() && p <= mc_space->top(), "must be");
380-
*adapter_trampoline = NULL;
381-
m->set_adapter_trampoline(to_target(adapter_trampoline));
382-
}
383-
}
384-
385-
guarantee(p <= mc_space->top(), "Estimate of trampoline size is insufficient");
386-
}
387-
388332
void DynamicArchiveBuilder::sort_methods() {
389333
InstanceKlass::disable_method_binary_search();
390334
for (int i = 0; i < klasses()->length(); i++) {

src/hotspot/share/memory/metaspaceShared.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,9 @@ void VM_PopulateDumpSharedSpace::doit() {
770770

771771
builder.relocate_well_known_klasses();
772772

773+
log_info(cds)("Update method trampolines");
774+
builder.update_method_trampolines();
775+
773776
log_info(cds)("Make classes shareable");
774777
builder.make_klasses_shareable();
775778

src/hotspot/share/oops/method.cpp

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,17 +1107,9 @@ void Method::unlink_method() {
11071107
_i2i_entry = Interpreter::entry_for_cds_method(methodHandle(Thread::current(), this));
11081108
_from_interpreted_entry = _i2i_entry;
11091109

1110-
if (DynamicDumpSharedSpaces) {
1111-
assert(_from_compiled_entry != NULL, "sanity");
1112-
} else {
1113-
// TODO: Simplify the adapter trampoline allocation for static archiving.
1114-
// Remove the use of CDSAdapterHandlerEntry.
1115-
CDSAdapterHandlerEntry* cds_adapter = (CDSAdapterHandlerEntry*)adapter();
1116-
constMethod()->set_adapter_trampoline(cds_adapter->get_adapter_trampoline());
1117-
_from_compiled_entry = cds_adapter->get_c2i_entry_trampoline();
1118-
assert(*((int*)_from_compiled_entry) == 0,
1119-
"must be NULL during dump time, to be initialized at run time");
1120-
}
1110+
assert(_from_compiled_entry != NULL, "sanity");
1111+
assert(*((int*)_from_compiled_entry) == 0,
1112+
"must be NULL during dump time, to be initialized at run time");
11211113

11221114
if (is_native()) {
11231115
*native_function_addr() = NULL;

src/hotspot/share/runtime/sharedRuntime.cpp

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2454,15 +2454,12 @@ class AdapterHandlerTable : public BasicHashtable<mtCode> {
24542454

24552455
public:
24562456
AdapterHandlerTable()
2457-
: BasicHashtable<mtCode>(293, (DumpSharedSpaces ? sizeof(CDSAdapterHandlerEntry) : sizeof(AdapterHandlerEntry))) { }
2457+
: BasicHashtable<mtCode>(293, (sizeof(AdapterHandlerEntry))) { }
24582458

24592459
// Create a new entry suitable for insertion in the table
24602460
AdapterHandlerEntry* new_entry(AdapterFingerPrint* fingerprint, address i2c_entry, address c2i_entry, address c2i_unverified_entry, address c2i_no_clinit_check_entry) {
24612461
AdapterHandlerEntry* entry = (AdapterHandlerEntry*)BasicHashtable<mtCode>::new_entry(fingerprint->compute_hash());
24622462
entry->init(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
2463-
if (DumpSharedSpaces) {
2464-
((CDSAdapterHandlerEntry*)entry)->init();
2465-
}
24662463
return entry;
24672464
}
24682465

@@ -3130,17 +3127,6 @@ void AdapterHandlerEntry::print_adapter_on(outputStream* st) const {
31303127
st->cr();
31313128
}
31323129

3133-
#if INCLUDE_CDS
3134-
3135-
void CDSAdapterHandlerEntry::init() {
3136-
assert(DumpSharedSpaces, "used during dump time only");
3137-
_c2i_entry_trampoline = (address)MetaspaceShared::misc_code_space_alloc(SharedRuntime::trampoline_size());
3138-
_adapter_trampoline = (AdapterHandlerEntry**)MetaspaceShared::misc_code_space_alloc(sizeof(AdapterHandlerEntry*));
3139-
};
3140-
3141-
#endif // INCLUDE_CDS
3142-
3143-
31443130
#ifndef PRODUCT
31453131

31463132
void AdapterHandlerLibrary::print_statistics() {

src/hotspot/share/runtime/sharedRuntime.hpp

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -679,20 +679,6 @@ class AdapterHandlerEntry : public BasicHashtableEntry<mtCode> {
679679
void print_adapter_on(outputStream* st) const;
680680
};
681681

682-
// This class is used only with DumpSharedSpaces==true. It holds extra information
683-
// that's used only during CDS dump time.
684-
// For details, see comments around Method::link_method()
685-
class CDSAdapterHandlerEntry: public AdapterHandlerEntry {
686-
address _c2i_entry_trampoline; // allocated from shared spaces "MC" region
687-
AdapterHandlerEntry** _adapter_trampoline; // allocated from shared spaces "MD" region
688-
689-
public:
690-
address get_c2i_entry_trampoline() const { return _c2i_entry_trampoline; }
691-
AdapterHandlerEntry** get_adapter_trampoline() const { return _adapter_trampoline; }
692-
void init() NOT_CDS_RETURN;
693-
};
694-
695-
696682
class AdapterHandlerLibrary: public AllStatic {
697683
private:
698684
static BufferBlob* _buffer; // the temporary code buffer in CodeCache

0 commit comments

Comments
 (0)