Skip to content

Commit 1357be9

Browse files
author
Ashutosh Mehra
committed
8371178: Preserve fast version of getfield and putfield in AOTCache
Reviewed-by: adinn, iklam
1 parent acc8a76 commit 1357be9

File tree

3 files changed

+95
-12
lines changed

3 files changed

+95
-12
lines changed

src/hotspot/share/cds/aotMetaspace.cpp

Lines changed: 93 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,13 @@
7777
#include "memory/universe.hpp"
7878
#include "nmt/memTracker.hpp"
7979
#include "oops/compressedKlass.hpp"
80+
#include "oops/constantPool.inline.hpp"
8081
#include "oops/instanceMirrorKlass.hpp"
8182
#include "oops/klass.inline.hpp"
8283
#include "oops/objArrayOop.hpp"
8384
#include "oops/oop.inline.hpp"
8485
#include "oops/oopHandle.hpp"
86+
#include "oops/resolvedFieldEntry.hpp"
8587
#include "oops/trainingData.hpp"
8688
#include "prims/jvmtiExport.hpp"
8789
#include "runtime/arguments.hpp"
@@ -519,33 +521,114 @@ void AOTMetaspace::serialize(SerializeClosure* soc) {
519521
soc->do_tag(666);
520522
}
521523

522-
static void rewrite_nofast_bytecode(const methodHandle& method) {
524+
// In AOTCache workflow, when dumping preimage, the constant pool entries are stored in unresolved state.
525+
// So the fast version of getfield/putfield needs to be converted to nofast version.
526+
// When dumping the final image in the assembly phase, these nofast versions are converted back to fast versions
527+
// if the constant pool entry refered by these bytecodes is stored in resolved state.
528+
// Same principle applies to static and dynamic archives. If the constant pool entry is in resolved state, then
529+
// the fast version of the bytecodes can be preserved, else use the nofast version.
530+
//
531+
// The fast versions of aload_0 (i.e. _fast_Xaccess_0) merges the bytecode pair (aload_0, fast_Xgetfield).
532+
// If the fast version of aload_0 is preserved in AOTCache, then the JVMTI notifications for field access and
533+
// breakpoint events will be skipped for the second bytecode (fast_Xgetfield) in the pair.
534+
// Same holds for fast versions of iload_0. So for these bytecodes, nofast version is used.
535+
static void rewrite_bytecodes(const methodHandle& method) {
536+
ConstantPool* cp = method->constants();
523537
BytecodeStream bcs(method);
538+
Bytecodes::Code new_code;
539+
540+
LogStreamHandle(Trace, aot, resolve) lsh;
541+
if (lsh.is_enabled()) {
542+
lsh.print("Rewriting bytecodes for ");
543+
method()->print_external_name(&lsh);
544+
lsh.print("\n");
545+
}
546+
524547
while (!bcs.is_last_bytecode()) {
525548
Bytecodes::Code opcode = bcs.next();
526-
switch (opcode) {
527-
case Bytecodes::_getfield: *bcs.bcp() = Bytecodes::_nofast_getfield; break;
528-
case Bytecodes::_putfield: *bcs.bcp() = Bytecodes::_nofast_putfield; break;
529-
case Bytecodes::_aload_0: *bcs.bcp() = Bytecodes::_nofast_aload_0; break;
530-
case Bytecodes::_iload: {
549+
// Use current opcode as the default value of new_code
550+
new_code = opcode;
551+
switch(opcode) {
552+
case Bytecodes::_getfield: {
553+
uint rfe_index = bcs.get_index_u2();
554+
bool is_resolved = cp->is_resolved(rfe_index, opcode);
555+
if (is_resolved) {
556+
assert(!CDSConfig::is_dumping_preimage_static_archive(), "preimage should not have resolved field references");
557+
ResolvedFieldEntry* rfe = cp->resolved_field_entry_at(bcs.get_index_u2());
558+
switch(rfe->tos_state()) {
559+
case btos:
560+
// fallthrough
561+
case ztos: new_code = Bytecodes::_fast_bgetfield; break;
562+
case atos: new_code = Bytecodes::_fast_agetfield; break;
563+
case itos: new_code = Bytecodes::_fast_igetfield; break;
564+
case ctos: new_code = Bytecodes::_fast_cgetfield; break;
565+
case stos: new_code = Bytecodes::_fast_sgetfield; break;
566+
case ltos: new_code = Bytecodes::_fast_lgetfield; break;
567+
case ftos: new_code = Bytecodes::_fast_fgetfield; break;
568+
case dtos: new_code = Bytecodes::_fast_dgetfield; break;
569+
default:
570+
ShouldNotReachHere();
571+
break;
572+
}
573+
} else {
574+
new_code = Bytecodes::_nofast_getfield;
575+
}
576+
break;
577+
}
578+
case Bytecodes::_putfield: {
579+
uint rfe_index = bcs.get_index_u2();
580+
bool is_resolved = cp->is_resolved(rfe_index, opcode);
581+
if (is_resolved) {
582+
assert(!CDSConfig::is_dumping_preimage_static_archive(), "preimage should not have resolved field references");
583+
ResolvedFieldEntry* rfe = cp->resolved_field_entry_at(bcs.get_index_u2());
584+
switch(rfe->tos_state()) {
585+
case btos: new_code = Bytecodes::_fast_bputfield; break;
586+
case ztos: new_code = Bytecodes::_fast_zputfield; break;
587+
case atos: new_code = Bytecodes::_fast_aputfield; break;
588+
case itos: new_code = Bytecodes::_fast_iputfield; break;
589+
case ctos: new_code = Bytecodes::_fast_cputfield; break;
590+
case stos: new_code = Bytecodes::_fast_sputfield; break;
591+
case ltos: new_code = Bytecodes::_fast_lputfield; break;
592+
case ftos: new_code = Bytecodes::_fast_fputfield; break;
593+
case dtos: new_code = Bytecodes::_fast_dputfield; break;
594+
default:
595+
ShouldNotReachHere();
596+
break;
597+
}
598+
} else {
599+
new_code = Bytecodes::_nofast_putfield;
600+
}
601+
break;
602+
}
603+
case Bytecodes::_aload_0:
604+
// Revert _fast_Xaccess_0 or _aload_0 to _nofast_aload_0
605+
new_code = Bytecodes::_nofast_aload_0;
606+
break;
607+
case Bytecodes::_iload:
531608
if (!bcs.is_wide()) {
532-
*bcs.bcp() = Bytecodes::_nofast_iload;
609+
new_code = Bytecodes::_nofast_iload;
533610
}
534611
break;
612+
default:
613+
break;
535614
}
536-
default: break;
615+
if (opcode != new_code) {
616+
*bcs.bcp() = new_code;
617+
if (lsh.is_enabled()) {
618+
lsh.print_cr("%d:%s -> %s", bcs.bci(), Bytecodes::name(opcode), Bytecodes::name(new_code));
619+
}
537620
}
538621
}
539622
}
540623

541624
// [1] Rewrite all bytecodes as needed, so that the ConstMethod* will not be modified
542625
// at run time by RewriteBytecodes/RewriteFrequentPairs
543626
// [2] Assign a fingerprint, so one doesn't need to be assigned at run-time.
544-
void AOTMetaspace::rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread* thread, InstanceKlass* ik) {
627+
void AOTMetaspace::rewrite_bytecodes_and_calculate_fingerprints(Thread* thread, InstanceKlass* ik) {
545628
for (int i = 0; i < ik->methods()->length(); i++) {
546629
methodHandle m(thread, ik->methods()->at(i));
547630
if (ik->can_be_verified_at_dumptime() && ik->is_linked()) {
548-
rewrite_nofast_bytecode(m);
631+
rewrite_bytecodes(m);
549632
}
550633
Fingerprinter fp(m);
551634
// The side effect of this call sets method's fingerprint field.

src/hotspot/share/cds/aotMetaspace.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ class AOTMetaspace : AllStatic {
144144
// (Heap region alignments are decided by GC).
145145
static size_t core_region_alignment();
146146
static size_t protection_zone_size();
147-
static void rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread* thread, InstanceKlass* ik);
147+
static void rewrite_bytecodes_and_calculate_fingerprints(Thread* thread, InstanceKlass* ik);
148148
// print loaded classes names to file.
149149
static void dump_loaded_classes(const char* file_name, TRAPS);
150150
#endif

src/hotspot/share/cds/archiveBuilder.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -952,7 +952,7 @@ void ArchiveBuilder::make_klasses_shareable() {
952952
}
953953
}
954954

955-
AOTMetaspace::rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread::current(), ik);
955+
AOTMetaspace::rewrite_bytecodes_and_calculate_fingerprints(Thread::current(), ik);
956956
ik->remove_unshareable_info();
957957
}
958958

0 commit comments

Comments
 (0)