src/share/vm/runtime/sharedRuntime.cpp
Print this page
rev 2893 : 7121756: Improve C1 inlining policy by using profiling at call sites
Summary: profile based recompilation of methods with C1 with more inlining.
Reviewed-by:
@@ -76,18 +76,23 @@
# include "nativeInst_ppc.hpp"
# include "vmreg_ppc.inline.hpp"
#endif
#ifdef COMPILER1
#include "c1/c1_Runtime1.hpp"
+#include "runtime/compilationPolicy.hpp"
#endif
// Shared stub locations
RuntimeStub* SharedRuntime::_wrong_method_blob;
RuntimeStub* SharedRuntime::_ic_miss_blob;
RuntimeStub* SharedRuntime::_resolve_opt_virtual_call_blob;
RuntimeStub* SharedRuntime::_resolve_virtual_call_blob;
RuntimeStub* SharedRuntime::_resolve_static_call_blob;
+#ifdef COMPILER1
+RuntimeStub* SharedRuntime::_resolve_profile_call_blob;
+RuntimeStub* SharedRuntime::_resolve_static_profile_call_blob;
+#endif
DeoptimizationBlob* SharedRuntime::_deopt_blob;
RicochetBlob* SharedRuntime::_ricochet_blob;
SafepointBlob* SharedRuntime::_polling_page_safepoint_handler_blob;
@@ -103,10 +108,14 @@
_wrong_method_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::handle_wrong_method), "wrong_method_stub");
_ic_miss_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::handle_wrong_method_ic_miss), "ic_miss_stub");
_resolve_opt_virtual_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_opt_virtual_call_C), "resolve_opt_virtual_call");
_resolve_virtual_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_virtual_call_C), "resolve_virtual_call");
_resolve_static_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_static_call_C), "resolve_static_call");
+#ifdef COMPILER1
+ _resolve_profile_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_profile_call_C), "resolve_profile_call");
+ _resolve_static_profile_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_static_profile_call_C),"resolve_static_profile_call");
+#endif
_polling_page_safepoint_handler_blob = generate_handler_blob(CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception), false);
_polling_page_return_handler_blob = generate_handler_blob(CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception), true);
generate_ricochet_blob();
@@ -1184,10 +1193,31 @@
methodHandle callee_method = call_info.selected_method();
assert((!is_virtual && invoke_code == Bytecodes::_invokestatic) ||
( is_virtual && invoke_code != Bytecodes::_invokestatic), "inconsistent bytecode");
+ bool is_profiled = false;
+
+#ifdef COMPILER1
+ is_profiled = caller_nm->is_profiled_call(caller_frame.pc());
+ if (is_profiled) {
+ if (callee_method->code_size() > SimpleProfiledCompPolicy::max_inline_size()) {
+ is_profiled = false;
+ }
+ if (is_profiled) {
+ vframeStream vfst(thread);
+ methodOop m = vfst.method();
+ int bci = vfst.bci();
+
+ CounterData* profile = m->method_data()->bci_to_data(bci)->as_CounterData();
+
+ profile->init_if_first_seen();
+ }
+ }
+#endif
+
+
#ifndef PRODUCT
// tracing/debugging/statistics
int *addr = (is_optimized) ? (&_resolve_opt_virtual_ctr) :
(is_virtual) ? (&_resolve_virtual_ctr) :
(&_resolve_static_ctr);
@@ -1232,15 +1262,15 @@
if (is_virtual) {
assert(receiver.not_null(), "sanity check");
bool static_bound = call_info.resolved_method()->can_be_statically_bound();
KlassHandle h_klass(THREAD, receiver->klass());
CompiledIC::compute_monomorphic_entry(callee_method, h_klass,
- is_optimized, static_bound, virtual_call_info,
+ is_optimized, static_bound, virtual_call_info, is_profiled,
CHECK_(methodHandle()));
} else {
// static call
- CompiledStaticCall::compute_entry(callee_method, static_call_info);
+ CompiledStaticCall::compute_entry(callee_method, static_call_info, is_profiled);
}
// grab lock, check for deoptimization and potentially patch caller
{
MutexLocker ml_patch(CompiledIC_lock);
@@ -1258,10 +1288,22 @@
#endif
if (is_virtual) {
CompiledIC* inline_cache = CompiledIC_before(caller_frame.pc());
if (inline_cache->is_clean()) {
inline_cache->set_to_monomorphic(virtual_call_info);
+#ifdef COMPILER1
+ if (is_profiled && !is_optimized) {
+ assert(invoke_code == Bytecodes::_invokevirtual || invoke_code == Bytecodes::_invokeinterface, "unexpected call");
+ vframeStream vfst(thread);
+ methodOop m = vfst.method();
+ int bci = vfst.bci();
+
+ VirtualCallData* profile = m->method_data()->bci_to_data(bci)->as_VirtualCallData();
+
+ profile->new_receiver(receiver);
+ }
+#endif
}
} else {
CompiledStaticCall* ssc = compiledStaticCall_before(caller_frame.pc());
if (ssc->is_clean()) ssc->set(static_call_info);
}
@@ -1389,13 +1431,79 @@
// return compiled code entry point after potential safepoints
assert(callee_method->verified_code_entry() != NULL, " Jump to zero!");
return callee_method->verified_code_entry();
JRT_END
+#ifdef COMPILER1
+methodHandle SharedRuntime::resolve_profile_helper(JavaThread *thread, TRAPS) {
+ ResourceMark rm(thread);
+ RegisterMap cbl_map(thread, false);
+ frame caller_frame = thread->last_frame().sender(&cbl_map);
+
+ CodeBlob* cb = caller_frame.cb();
+ guarantee(cb != NULL && cb->is_nmethod(), "must be called from nmethod");
+ nmethodLocker caller_lock((nmethod*)cb);
+ CallInfo call_info;
+ Bytecodes::Code invoke_code = Bytecodes::_illegal;
+ Handle receiver = find_callee_info(thread, invoke_code,
+ call_info, CHECK_(methodHandle()));
+
+ return call_info.selected_method();
+}
+
+JRT_BLOCK_ENTRY(address, SharedRuntime::resolve_profile_call_C(JavaThread *thread ))
+ methodHandle callee_method;
+ JRT_BLOCK
+ {
+ callee_method = resolve_profile_helper(thread, CHECK_NULL);
+
+ bool fix_call = SimpleProfiledCompPolicy::profile_overflow_event(thread, CHECK_NULL);
+
+ if (fix_call) {
+ ResourceMark rm;
+ RegisterMap map(thread, false);
+ frame fr = thread->last_frame().sender(&map);
+
+ MutexLocker ml_patch(CompiledIC_lock);
+
+ CompiledIC* inline_cache = CompiledIC_before(fr.pc());
+
+ inline_cache->drop_profiling();
+ }
+ thread->set_vm_result(callee_method());
+ }
+ JRT_BLOCK_END
+ // return compiled code entry point after potential safepoints
+ assert(callee_method->verified_code_entry() != NULL, " Jump to zero!");
+ return callee_method->verified_code_entry();
+JRT_END
+
+JRT_BLOCK_ENTRY(address, SharedRuntime::resolve_static_profile_call_C(JavaThread *thread ))
+ methodHandle callee_method;
+ JRT_BLOCK
+ {
+ callee_method = resolve_profile_helper(thread, CHECK_NULL);
+
+ bool fix_call = SimpleProfiledCompPolicy::profile_overflow_event(thread, CHECK_NULL);
+ if (fix_call) {
+ RegisterMap map(thread, false);
+ frame fr = thread->last_frame().sender(&map);
+ MutexLocker ml_patch(CompiledIC_lock);
+ CompiledStaticCall* ssc = compiledStaticCall_before(fr.pc());
+ ssc->drop_profiling();
+ }
+ thread->set_vm_result(callee_method());
+ }
+ JRT_BLOCK_END
+ // return compiled code entry point after potential safepoints
+ assert(callee_method->verified_code_entry() != NULL, " Jump to zero!");
+ return callee_method->verified_code_entry();
+JRT_END
+#endif
methodHandle SharedRuntime::handle_ic_miss_helper(JavaThread *thread, TRAPS) {
ResourceMark rm(thread);
CallInfo call_info;
Bytecodes::Code bc;
@@ -1498,24 +1606,52 @@
}
}
if (should_be_mono) {
+ bool is_profiled = false;
+#ifdef COMPILER1
+ is_profiled = ((nmethod*)cb)->is_profiled_call(caller_frame.pc());
+#endif
// We have a path that was monomorphic but was going interpreted
// and now we have (or had) a compiled entry. We correct the IC
// by using a new icBuffer.
CompiledICInfo info;
KlassHandle receiver_klass(THREAD, receiver()->klass());
inline_cache->compute_monomorphic_entry(callee_method,
receiver_klass,
inline_cache->is_optimized(),
false,
- info, CHECK_(methodHandle()));
+ info, is_profiled, CHECK_(methodHandle()));
+#ifdef COMPILER1
+ if (is_profiled) {
+ vframeStream vfst(thread);
+ methodOop m = vfst.method();
+ int bci = vfst.bci();
+
+ CounterData* profile = m->method_data()->bci_to_data(bci)->as_CounterData();
+
+ profile->init_if_first_seen();
+ }
+#endif
+
inline_cache->set_to_monomorphic(info);
} else if (!inline_cache->is_megamorphic() && !inline_cache->is_clean()) {
// Change to megamorphic
inline_cache->set_to_megamorphic(&call_info, bc, CHECK_(methodHandle()));
+#ifdef COMPILER1
+ if (((nmethod*)cb)->is_profiled_call(caller_frame.pc())) {
+ vframeStream vfst(thread);
+ methodOop m = vfst.method();
+ int bci = vfst.bci();
+
+ VirtualCallData* profile = m->method_data()->bci_to_data(bci)->as_VirtualCallData();
+
+ profile->new_receiver(receiver);
+ }
+#endif
+
} else {
// Either clean or megamorphic
}
}
} // Release CompiledIC_lock
@@ -1679,10 +1815,15 @@
// handle adapters are doing the required MethodHandle chain work.
if (nm->is_method_handle_return(return_pc)) {
return;
}
+ bool is_profiled = false;
+#ifdef COMPILER1
+ is_profiled = nm->is_profiled_call(caller_pc+frame::pc_return_offset);
+#endif
+
// There is a benign race here. We could be attempting to patch to a compiled
// entry point at the same time the callee is being deoptimized. If that is
// the case then entry_point may in fact point to a c2i and we'd patch the
// call site with the same old data. clear_code will set code() to NULL
// at the end of it. If we happen to see that NULL then we can skip trying
@@ -1716,21 +1857,29 @@
typ != relocInfo::opt_virtual_call_type &&
typ != relocInfo::static_stub_type) {
return;
}
address destination = call->destination();
- if (destination != entry_point) {
+ address stub = NULL;
+ if (is_profiled) {
+ stub = CompiledProfile::find_profile_stub(call);
+ }
+ if (destination != entry_point && !CompiledProfile::is_call_to_stub(call, stub)) {
CodeBlob* callee = CodeCache::find_blob(destination);
// callee == cb seems weird. It means calling interpreter thru stub.
if (callee == cb || callee->is_adapter_blob()) {
// static call or optimized virtual
if (TraceCallFixup) {
tty->print("fixup callsite at " INTPTR_FORMAT " to compiled code for", caller_pc);
moop->print_short_name(tty);
tty->print_cr(" to " INTPTR_FORMAT, entry_point);
}
+ if (is_profiled) {
+ CompiledProfile::set_up_profiling(call, stub, entry_point);
+ } else {
call->set_destination_mt_safe(entry_point);
+ }
} else {
if (TraceCallFixup) {
tty->print("failed to fixup callsite at " INTPTR_FORMAT " to compiled code for", caller_pc);
moop->print_short_name(tty);
tty->print_cr(" to " INTPTR_FORMAT, entry_point);