Skip to content

Commit c3da348

Browse files
author
Michael Haas
committed
[GR-68488] Extend JVMCI to express fixed binding
PullRequest: labsjdk-ce/211
2 parents c9fd5a4 + 845dd73 commit c3da348

File tree

15 files changed

+283
-24
lines changed

15 files changed

+283
-24
lines changed

src/hotspot/cpu/aarch64/jvmciCodeInstaller_aarch64.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong forei
124124
JVMCI_event_3("relocating (foreign call) at " PTR_FORMAT, p2i(inst));
125125
}
126126

127-
void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &cbuf, methodHandle& method, jint pc_offset, JVMCI_TRAPS) {
127+
void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &cbuf, methodHandle& method, jint pc_offset, int method_index, JVMCI_TRAPS) {
128128
NativeCall* call = nullptr;
129129
switch (_next_call_type) {
130130
case INLINE_INVOKE:
@@ -133,21 +133,21 @@ void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &cbuf, methodHandle& metho
133133
case INVOKEINTERFACE: {
134134
assert(!method->is_static(), "cannot call static method with invokeinterface");
135135
call = nativeCall_at(_instructions->start() + pc_offset);
136-
_instructions->relocate(call->instruction_address(), virtual_call_Relocation::spec(_invoke_mark_pc));
136+
_instructions->relocate(call->instruction_address(), virtual_call_Relocation::spec(_invoke_mark_pc, method_index));
137137
call->trampoline_jump(cbuf, SharedRuntime::get_resolve_virtual_call_stub(), JVMCI_CHECK);
138138
break;
139139
}
140140
case INVOKESTATIC: {
141141
assert(method->is_static(), "cannot call non-static method with invokestatic");
142142
call = nativeCall_at(_instructions->start() + pc_offset);
143-
_instructions->relocate(call->instruction_address(), relocInfo::static_call_type);
143+
_instructions->relocate(call->instruction_address(), relocInfo::static_call_type, 0, method_index);
144144
call->trampoline_jump(cbuf, SharedRuntime::get_resolve_static_call_stub(), JVMCI_CHECK);
145145
break;
146146
}
147147
case INVOKESPECIAL: {
148148
assert(!method->is_static(), "cannot call static method with invokespecial");
149149
call = nativeCall_at(_instructions->start() + pc_offset);
150-
_instructions->relocate(call->instruction_address(), relocInfo::opt_virtual_call_type);
150+
_instructions->relocate(call->instruction_address(), relocInfo::opt_virtual_call_type, 0, method_index);
151151
call->trampoline_jump(cbuf, SharedRuntime::get_resolve_opt_virtual_call_stub(), JVMCI_CHECK);
152152
break;
153153
}

src/hotspot/cpu/arm/jvmciCodeInstaller_arm.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong forei
5252
Unimplemented();
5353
}
5454

55-
void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &cbuf, Handle hotspot_method, jint pc_offset, TRAPS) {
55+
void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &cbuf, Handle hotspot_method, jint pc_offset, int method_index, TRAPS) {
5656
Unimplemented();
5757
}
5858

src/hotspot/cpu/ppc/jvmciCodeInstaller_ppc.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong forei
5151
Unimplemented();
5252
}
5353

54-
void CodeInstaller::pd_relocate_JavaMethod(Handle hotspot_method, jint pc_offset, TRAPS) {
54+
void CodeInstaller::pd_relocate_JavaMethod(Handle hotspot_method, jint pc_offset, int method_index, TRAPS) {
5555
Unimplemented();
5656
}
5757

src/hotspot/cpu/riscv/jvmciCodeInstaller_riscv.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong forei
100100
JVMCI_event_3("relocating (foreign call) at " PTR_FORMAT, p2i(inst));
101101
}
102102

103-
void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &cbuf, methodHandle& method, jint pc_offset, JVMCI_TRAPS) {
103+
void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &cbuf, methodHandle& method, jint pc_offset, int method_index, JVMCI_TRAPS) {
104104
Unimplemented();
105105
}
106106

src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong forei
153153
JVMCI_event_3("relocating (foreign call) at " PTR_FORMAT, p2i(inst));
154154
}
155155

156-
void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &, methodHandle& method, jint pc_offset, JVMCI_TRAPS) {
156+
void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &, methodHandle& method, jint pc_offset, int method_index, JVMCI_TRAPS) {
157157
NativeCall* call = nullptr;
158158
switch (_next_call_type) {
159159
case INLINE_INVOKE:
@@ -165,7 +165,7 @@ void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &, methodHandle& method, j
165165
call = nativeCall_at(_instructions->start() + pc_offset);
166166
call->set_destination(SharedRuntime::get_resolve_virtual_call_stub());
167167
_instructions->relocate(call->instruction_address(),
168-
virtual_call_Relocation::spec(_invoke_mark_pc),
168+
virtual_call_Relocation::spec(_invoke_mark_pc, method_index),
169169
Assembler::call32_operand);
170170
break;
171171
}
@@ -175,15 +175,15 @@ void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &, methodHandle& method, j
175175
call = nativeCall_at(_instructions->start() + pc_offset);
176176
call->set_destination(SharedRuntime::get_resolve_static_call_stub());
177177
_instructions->relocate(call->instruction_address(),
178-
relocInfo::static_call_type, Assembler::call32_operand);
178+
relocInfo::static_call_type, Assembler::call32_operand, method_index);
179179
break;
180180
}
181181
case INVOKESPECIAL: {
182182
assert(!method->is_static(), "cannot call static method with invokespecial");
183183
call = nativeCall_at(_instructions->start() + pc_offset);
184184
call->set_destination(SharedRuntime::get_resolve_opt_virtual_call_stub());
185185
_instructions->relocate(call->instruction_address(),
186-
relocInfo::opt_virtual_call_type, Assembler::call32_operand);
186+
relocInfo::opt_virtual_call_type, Assembler::call32_operand, method_index);
187187
break;
188188
}
189189
default:

src/hotspot/share/jvmci/jvmciCodeInstaller.cpp

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,7 +1141,7 @@ int CodeInstaller::map_jvmci_bci(int bci) {
11411141
return bci;
11421142
}
11431143

1144-
void CodeInstaller::record_scope(jint pc_offset, HotSpotCompiledCodeStream* stream, u1 debug_info_flags, bool full_info, bool is_mh_invoke, bool return_oop, JVMCI_TRAPS) {
1144+
void CodeInstaller::record_scope(jint pc_offset, HotSpotCompiledCodeStream* stream, u1 debug_info_flags, bool full_info, bool is_mh_invoke, bool return_oop, CallSiteBindingContext* binding_context, JVMCI_TRAPS) {
11451145
if (full_info) {
11461146
read_virtual_objects(stream, JVMCI_CHECK);
11471147
}
@@ -1170,6 +1170,11 @@ void CodeInstaller::record_scope(jint pc_offset, HotSpotCompiledCodeStream* stre
11701170

11711171
if (bci >= 0) {
11721172
reexecute = !is_set(frame_flags, DIF_DURING_CALL);
1173+
if (i == depth - 1 && binding_context != nullptr) {
1174+
binding_context->bci = bci;
1175+
binding_context->caller = method;
1176+
binding_context->reexecute = reexecute;
1177+
}
11731178
}
11741179

11751180
GrowableArray<ScopeValue*>* locals = read_local_or_stack_values(stream, frame_flags, true, JVMCI_CHECK);
@@ -1199,7 +1204,7 @@ void CodeInstaller::site_Safepoint(CodeBuffer& buffer, jint pc_offset, HotSpotCo
11991204
u1 flags = stream->read_u1("debugInfo:flags");
12001205
OopMap *map = create_oop_map(stream, flags, JVMCI_CHECK);
12011206
_debug_recorder->add_safepoint(pc_offset, map);
1202-
record_scope(pc_offset, stream, flags, true, JVMCI_CHECK);
1207+
record_scope(pc_offset, stream, flags, true, nullptr, JVMCI_CHECK);
12031208
_debug_recorder->end_safepoint(pc_offset);
12041209
if (_orig_pc_offset < 0) {
12051210
JVMCI_ERROR("method contains safepoint, but has no deopt rescue slot");
@@ -1215,15 +1220,32 @@ void CodeInstaller::site_Safepoint(CodeBuffer& buffer, jint pc_offset, HotSpotCo
12151220
void CodeInstaller::site_Infopoint(CodeBuffer& buffer, jint pc_offset, HotSpotCompiledCodeStream* stream, JVMCI_TRAPS) {
12161221
u1 flags = stream->read_u1("debugInfo:flags");
12171222
_debug_recorder->add_non_safepoint(pc_offset);
1218-
record_scope(pc_offset, stream, flags, false, JVMCI_CHECK);
1223+
record_scope(pc_offset, stream, flags, false, nullptr, JVMCI_CHECK);
12191224
_debug_recorder->end_non_safepoint(pc_offset);
12201225
}
12211226

1227+
// see CallGenerator::is_inlined_method_handle_intrinsic
1228+
bool is_inlined_method_handle_intrinsic(JavaThread* thread, methodHandle& caller, int bci, methodHandle& method) {
1229+
constantPoolHandle cpool(thread, caller->constants());
1230+
InstanceKlass* pool_holder = cpool->pool_holder();
1231+
Bytecode_invoke bytecode(caller, bci);
1232+
Method* symbolic_info = JVMCIRuntime::get_method_by_index(cpool, bytecode.index(), caller->java_code_at(bci), pool_holder);
1233+
return symbolic_info->is_method_handle_intrinsic() && !method->is_method_handle_intrinsic();
1234+
}
1235+
1236+
// computation if binding is necessary corresponds to SharedRuntime::find_callee_info_helper
1237+
bool bind_call(JavaThread* thread, CallSiteBindingContext& binding_context, methodHandle& method, JVMCI_TRAPS) {
1238+
// TODO for Valhalla: if method has scalarized parameters bind as well
1239+
return binding_context.reexecute || is_inlined_method_handle_intrinsic(thread, binding_context.caller, binding_context.bci, method);
1240+
}
1241+
12221242
void CodeInstaller::site_Call(CodeBuffer& buffer, u1 tag, jint pc_offset, HotSpotCompiledCodeStream* stream, JVMCI_TRAPS) {
12231243
JavaThread* thread = stream->thread();
12241244
jlong target = stream->read_u8("target");
12251245
methodHandle method;
12261246
bool direct_call = false;
1247+
int method_index = 0;
1248+
CallSiteBindingContext binding_context;
12271249
if (tag == SITE_CALL) {
12281250
method = methodHandle(thread, (Method*) target);
12291251
assert(Method::is_valid_method(method()), "invalid method");
@@ -1249,17 +1271,20 @@ void CodeInstaller::site_Call(CodeBuffer& buffer, u1 tag, jint pc_offset, HotSpo
12491271
(MethodHandles::is_signature_polymorphic(iid) && MethodHandles::is_signature_polymorphic_intrinsic(iid)));
12501272
}
12511273
bool return_oop = method->is_returning_oop();
1252-
record_scope(next_pc_offset, stream, flags, true, is_mh_invoke, return_oop, JVMCI_CHECK);
1274+
record_scope(next_pc_offset, stream, flags, true, is_mh_invoke, return_oop, &binding_context, JVMCI_CHECK);
12531275
} else {
1254-
record_scope(next_pc_offset, stream, flags, true, JVMCI_CHECK);
1276+
record_scope(next_pc_offset, stream, flags, true, &binding_context, JVMCI_CHECK);
12551277
}
12561278
}
12571279

12581280
if (tag != SITE_CALL) {
12591281
jlong foreign_call_destination = target;
12601282
CodeInstaller::pd_relocate_ForeignCall(inst, foreign_call_destination, JVMCI_CHECK);
12611283
} else {
1262-
CodeInstaller::pd_relocate_JavaMethod(buffer, method, pc_offset, JVMCI_CHECK);
1284+
if (direct_call && bind_call(thread, binding_context, method, __jvmci_env__)) {
1285+
method_index = _oop_recorder->find_index(method());
1286+
}
1287+
CodeInstaller::pd_relocate_JavaMethod(buffer, method, pc_offset, method_index, JVMCI_CHECK);
12631288
if (_next_call_type == INVOKESTATIC || _next_call_type == INVOKESPECIAL) {
12641289
// Need a static call stub for transitions from compiled to interpreted.
12651290
MacroAssembler masm(&buffer);

src/hotspot/share/jvmci/jvmciCodeInstaller.hpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,17 @@ class HotSpotCompiledCodeStream : public ResourceObj {
140140
#undef checked_read
141141
};
142142

143+
// Helper class that gathers context information to determine
144+
// whether a method call needs to be bound at the call site.
145+
class CallSiteBindingContext {
146+
public:
147+
int bci;
148+
methodHandle caller;
149+
bool reexecute;
150+
151+
CallSiteBindingContext() : bci(0), caller(), reexecute(false) {}
152+
};
153+
143154
// Converts a HotSpotCompiledCode to a CodeBlob or an nmethod.
144155
class CodeInstaller : public StackObj {
145156
friend class JVMCIVMStructs;
@@ -332,7 +343,7 @@ class CodeInstaller : public StackObj {
332343
void pd_patch_MetaspaceConstant(int pc_offset, HotSpotCompiledCodeStream* stream, u1 tag, JVMCI_TRAPS);
333344
void pd_patch_DataSectionReference(int pc_offset, int data_offset, JVMCI_TRAPS);
334345
void pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination, JVMCI_TRAPS);
335-
void pd_relocate_JavaMethod(CodeBuffer &cbuf, methodHandle& method, jint pc_offset, JVMCI_TRAPS);
346+
void pd_relocate_JavaMethod(CodeBuffer &cbuf, methodHandle& method, jint pc_offset, int method_index, JVMCI_TRAPS);
336347
bool pd_relocate(address pc, jint mark);
337348

338349
public:
@@ -411,10 +422,10 @@ class CodeInstaller : public StackObj {
411422
void record_oop_patch(HotSpotCompiledCodeStream* stream, address dest, u1 read_tag, bool narrow, JVMCI_TRAPS);
412423

413424
// full_info: if false, only BytecodePosition is in stream otherwise all DebugInfo is in stream
414-
void record_scope(jint pc_offset, HotSpotCompiledCodeStream* stream, u1 debug_info_flags, bool full_info, bool is_mh_invoke, bool return_oop, JVMCI_TRAPS);
425+
void record_scope(jint pc_offset, HotSpotCompiledCodeStream* stream, u1 debug_info_flags, bool full_info, bool is_mh_invoke, bool return_oop, CallSiteBindingContext* binding_context, JVMCI_TRAPS);
415426

416-
void record_scope(jint pc_offset, HotSpotCompiledCodeStream* stream, u1 debug_info_flags, bool full_info, JVMCI_TRAPS) {
417-
record_scope(pc_offset, stream, debug_info_flags, full_info, false /* is_mh_invoke */, false /* return_oop */, JVMCIENV);
427+
void record_scope(jint pc_offset, HotSpotCompiledCodeStream* stream, u1 debug_info_flags, bool full_info, CallSiteBindingContext* binding_context, JVMCI_TRAPS) {
428+
record_scope(pc_offset, stream, debug_info_flags, full_info, false /* is_mh_invoke */, false /* return_oop */, binding_context, JVMCIENV);
418429
}
419430
void record_object_value(ObjectValue* sv, HotSpotCompiledCodeStream* stream, JVMCI_TRAPS);
420431

src/hotspot/share/jvmci/jvmciRuntime.cpp

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ static bool caller_is_deopted() {
7878

7979
// Stress deoptimization
8080
static void deopt_caller() {
81-
if ( !caller_is_deopted()) {
81+
if (!caller_is_deopted()) {
8282
JavaThread* thread = JavaThread::current();
8383
RegisterMap reg_map(thread,
8484
RegisterMap::UpdateMap::skip,
@@ -91,6 +91,34 @@ static void deopt_caller() {
9191
}
9292
}
9393

94+
static bool caller_of_caller_is_deopted() {
95+
JavaThread* thread = JavaThread::current();
96+
RegisterMap reg_map(thread,
97+
RegisterMap::UpdateMap::skip,
98+
RegisterMap::ProcessFrames::include,
99+
RegisterMap::WalkContinuation::skip);
100+
frame runtime_frame = thread->last_frame();
101+
frame caller_frame = runtime_frame.sender(&reg_map);
102+
frame caller_of_caller_frame = caller_frame.sender(&reg_map);
103+
assert(caller_of_caller_frame.is_compiled_frame(), "must be compiled");
104+
return caller_of_caller_frame.is_deoptimized_frame();
105+
}
106+
107+
static void deopt_caller_of_caller() {
108+
if (!caller_of_caller_is_deopted()) {
109+
JavaThread* thread = JavaThread::current();
110+
RegisterMap reg_map(thread,
111+
RegisterMap::UpdateMap::skip,
112+
RegisterMap::ProcessFrames::include,
113+
RegisterMap::WalkContinuation::skip);
114+
frame runtime_frame = thread->last_frame();
115+
frame caller_frame = runtime_frame.sender(&reg_map);
116+
frame caller_of_caller_frame = caller_frame.sender(&reg_map);
117+
Deoptimization::deoptimize_frame(thread, caller_of_caller_frame.id(), Deoptimization::Reason_constraint);
118+
assert(caller_of_caller_is_deopted(), "Must be deoptimized");
119+
}
120+
}
121+
94122
// Manages a scope for a JVMCI runtime call that attempts a heap allocation.
95123
// If there is a pending OutOfMemoryError upon closing the scope and the runtime
96124
// call is of the variety where allocation failure returns null without an
@@ -714,6 +742,11 @@ JRT_ENTRY(jint, JVMCIRuntime::test_deoptimize_call_int(JavaThread* current, int
714742
return (jint) value;
715743
JRT_END
716744

745+
JRT_ENTRY(jint, JVMCIRuntime::test_deoptimize_caller_of_caller(JavaThread* current, int value))
746+
deopt_caller_of_caller();
747+
return (jint) value;
748+
JRT_END
749+
717750

718751
// Implementation of JVMCI.initializeRuntime()
719752
// When called from libjvmci, `libjvmciOrHotspotEnv` is a libjvmci env so use JVM_ENTRY_NO_ENV.

src/hotspot/share/jvmci/jvmciRuntime.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,5 +585,6 @@ class JVMCIRuntime: public CHeapObj<mtJVMCI> {
585585

586586
// Test only function
587587
static jint test_deoptimize_call_int(JavaThread* current, int value);
588+
static jint test_deoptimize_caller_of_caller(JavaThread* current, int value);
588589
};
589590
#endif // SHARE_JVMCI_JVMCIRUNTIME_HPP

src/hotspot/share/jvmci/vmStructs_jvmci.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -920,7 +920,8 @@
920920
SHENANDOAHGC_ONLY(declare_function(ShenandoahRuntime::write_barrier_pre)) \
921921
declare_function(JVMCIRuntime::validate_object) \
922922
\
923-
declare_function(JVMCIRuntime::test_deoptimize_call_int)
923+
declare_function(JVMCIRuntime::test_deoptimize_call_int) \
924+
declare_function(JVMCIRuntime::test_deoptimize_caller_of_caller)
924925

925926

926927
#if INCLUDE_G1GC

0 commit comments

Comments
 (0)