mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 19:14:38 +02:00
7042122: JSR 292: adjust various inline thresholds for JSR 292 API methods and method handle adapters
Reviewed-by: jrose, never, kvn
This commit is contained in:
parent
42e49be1bc
commit
fee8d7fca4
7 changed files with 95 additions and 51 deletions
|
@ -42,7 +42,7 @@ ciMethod* ciMethodHandle::get_adapter(bool is_invokedynamic) const {
|
|||
methodHandle callee(_callee->get_methodOop());
|
||||
// We catch all exceptions here that could happen in the method
|
||||
// handle compiler and stop the VM.
|
||||
MethodHandleCompiler mhc(h, callee, is_invokedynamic, THREAD);
|
||||
MethodHandleCompiler mhc(h, callee, call_profile()->count(), is_invokedynamic, THREAD);
|
||||
if (!HAS_PENDING_EXCEPTION) {
|
||||
methodHandle m = mhc.compile(THREAD);
|
||||
if (!HAS_PENDING_EXCEPTION) {
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#ifndef SHARE_VM_CI_CIMETHODHANDLE_HPP
|
||||
#define SHARE_VM_CI_CIMETHODHANDLE_HPP
|
||||
|
||||
#include "ci/ciCallProfile.hpp"
|
||||
#include "ci/ciInstance.hpp"
|
||||
#include "prims/methodHandles.hpp"
|
||||
|
||||
|
@ -34,6 +35,7 @@
|
|||
class ciMethodHandle : public ciInstance {
|
||||
private:
|
||||
ciMethod* _callee;
|
||||
ciCallProfile* _profile;
|
||||
|
||||
// Return an adapter for this MethodHandle.
|
||||
ciMethod* get_adapter(bool is_invokedynamic) const;
|
||||
|
@ -50,6 +52,9 @@ public:
|
|||
ciMethod* callee() const { return _callee; }
|
||||
void set_callee(ciMethod* m) { _callee = m; }
|
||||
|
||||
ciCallProfile* call_profile() const { return _profile; }
|
||||
void set_call_profile(ciCallProfile* profile) { _profile = profile; }
|
||||
|
||||
// Return an adapter for a MethodHandle call.
|
||||
ciMethod* get_method_handle_adapter() const {
|
||||
return get_adapter(false);
|
||||
|
|
|
@ -89,7 +89,7 @@ static bool is_init_with_ea(ciMethod* callee_method,
|
|||
}
|
||||
|
||||
// positive filter: should send be inlined? returns NULL, if yes, or rejection msg
|
||||
const char* InlineTree::shouldInline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result) const {
|
||||
const char* InlineTree::should_inline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result) const {
|
||||
// Allows targeted inlining
|
||||
if(callee_method->should_inline()) {
|
||||
*wci_result = *(WarmCallInfo::always_hot());
|
||||
|
@ -102,7 +102,6 @@ const char* InlineTree::shouldInline(ciMethod* callee_method, ciMethod* caller_m
|
|||
|
||||
// positive filter: should send be inlined? returns NULL (--> yes)
|
||||
// or rejection msg
|
||||
int max_size = C->max_inline_size();
|
||||
int size = callee_method->code_size();
|
||||
|
||||
// Check for too many throws (and not too huge)
|
||||
|
@ -120,9 +119,27 @@ const char* InlineTree::shouldInline(ciMethod* callee_method, ciMethod* caller_m
|
|||
return NULL; // size and frequency are represented in a new way
|
||||
}
|
||||
|
||||
int default_max_inline_size = C->max_inline_size();
|
||||
int inline_small_code_size = InlineSmallCode / 4;
|
||||
int max_inline_size = default_max_inline_size;
|
||||
|
||||
int call_site_count = method()->scale_count(profile.count());
|
||||
int invoke_count = method()->interpreter_invocation_count();
|
||||
assert( invoke_count != 0, "Require invokation count greater than zero");
|
||||
|
||||
// Bytecoded method handle adapters do not have interpreter
|
||||
// profiling data but only made up MDO data. Get the counter from
|
||||
// there.
|
||||
if (caller_method->is_method_handle_adapter()) {
|
||||
assert(method()->method_data_or_null(), "must have an MDO");
|
||||
ciMethodData* mdo = method()->method_data();
|
||||
ciProfileData* mha_profile = mdo->bci_to_data(caller_bci);
|
||||
assert(mha_profile, "must exist");
|
||||
CounterData* cd = mha_profile->as_CounterData();
|
||||
invoke_count = cd->count();
|
||||
call_site_count = invoke_count; // use the same value
|
||||
}
|
||||
|
||||
assert(invoke_count != 0, "require invocation count greater than zero");
|
||||
int freq = call_site_count / invoke_count;
|
||||
|
||||
// bump the max size if the call is frequent
|
||||
|
@ -130,8 +147,8 @@ const char* InlineTree::shouldInline(ciMethod* callee_method, ciMethod* caller_m
|
|||
(call_site_count >= InlineFrequencyCount) ||
|
||||
is_init_with_ea(callee_method, caller_method, C)) {
|
||||
|
||||
max_size = C->freq_inline_size();
|
||||
if (size <= max_size && TraceFrequencyInlining) {
|
||||
max_inline_size = C->freq_inline_size();
|
||||
if (size <= max_inline_size && TraceFrequencyInlining) {
|
||||
CompileTask::print_inline_indent(inline_depth());
|
||||
tty->print_cr("Inlined frequent method (freq=%d count=%d):", freq, call_site_count);
|
||||
CompileTask::print_inline_indent(inline_depth());
|
||||
|
@ -141,11 +158,11 @@ const char* InlineTree::shouldInline(ciMethod* callee_method, ciMethod* caller_m
|
|||
} else {
|
||||
// Not hot. Check for medium-sized pre-existing nmethod at cold sites.
|
||||
if (callee_method->has_compiled_code() &&
|
||||
callee_method->instructions_size(CompLevel_full_optimization) > InlineSmallCode/4)
|
||||
callee_method->instructions_size(CompLevel_full_optimization) > inline_small_code_size)
|
||||
return "already compiled into a medium method";
|
||||
}
|
||||
if (size > max_size) {
|
||||
if (max_size > C->max_inline_size())
|
||||
if (size > max_inline_size) {
|
||||
if (max_inline_size > default_max_inline_size)
|
||||
return "hot method too big";
|
||||
return "too big";
|
||||
}
|
||||
|
@ -154,7 +171,7 @@ const char* InlineTree::shouldInline(ciMethod* callee_method, ciMethod* caller_m
|
|||
|
||||
|
||||
// negative filter: should send NOT be inlined? returns NULL, ok to inline, or rejection msg
|
||||
const char* InlineTree::shouldNotInline(ciMethod *callee_method, ciMethod* caller_method, WarmCallInfo* wci_result) const {
|
||||
const char* InlineTree::should_not_inline(ciMethod *callee_method, ciMethod* caller_method, WarmCallInfo* wci_result) const {
|
||||
// negative filter: should send NOT be inlined? returns NULL (--> inline) or rejection msg
|
||||
if (!UseOldInlining) {
|
||||
const char* fail = NULL;
|
||||
|
@ -269,14 +286,13 @@ const char* InlineTree::try_to_inline(ciMethod* callee_method, ciMethod* caller_
|
|||
}
|
||||
|
||||
const char *msg = NULL;
|
||||
if ((msg = shouldInline(callee_method, caller_method, caller_bci,
|
||||
profile, wci_result)) != NULL) {
|
||||
msg = should_inline(callee_method, caller_method, caller_bci, profile, wci_result);
|
||||
if (msg != NULL)
|
||||
return msg;
|
||||
}
|
||||
if ((msg = shouldNotInline(callee_method, caller_method,
|
||||
wci_result)) != NULL) {
|
||||
|
||||
msg = should_not_inline(callee_method, caller_method, wci_result);
|
||||
if (msg != NULL)
|
||||
return msg;
|
||||
}
|
||||
|
||||
if (InlineAccessors && callee_method->is_accessor()) {
|
||||
// accessor methods are not subject to any of the following limits.
|
||||
|
@ -492,9 +508,8 @@ InlineTree *InlineTree::build_inline_tree_for_callee( ciMethod* callee_method, J
|
|||
new_depth_adjust -= 1; // don't count method handle calls from java.lang.invoke implem
|
||||
}
|
||||
if (new_depth_adjust != 0 && PrintInlining) {
|
||||
stringStream nm1; caller_jvms->method()->print_name(&nm1);
|
||||
stringStream nm2; callee_method->print_name(&nm2);
|
||||
tty->print_cr("discounting inlining depth from %s to %s", nm1.base(), nm2.base());
|
||||
CompileTask::print_inline_indent(inline_depth());
|
||||
tty->print_cr(" \\-> discounting inline depth");
|
||||
}
|
||||
if (new_depth_adjust != 0 && C->log()) {
|
||||
int id1 = C->log()->identify(caller_jvms->method());
|
||||
|
|
|
@ -74,6 +74,7 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
|
|||
// from more specific profile data which pertains to this inlining.
|
||||
// Right now, ignore the information in jvms->caller(), and do method[bci].
|
||||
ciCallProfile profile = jvms->method()->call_profile_at_bci(jvms->bci());
|
||||
Bytecodes::Code bytecode = jvms->method()->java_code_at_bci(jvms->bci());
|
||||
|
||||
// See how many times this site has been invoked.
|
||||
int site_count = profile.count();
|
||||
|
@ -116,7 +117,7 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
|
|||
// MethodHandle.invoke* are native methods which obviously don't
|
||||
// have bytecodes and so normal inlining fails.
|
||||
if (call_method->is_method_handle_invoke()) {
|
||||
if (jvms->method()->java_code_at_bci(jvms->bci()) != Bytecodes::_invokedynamic) {
|
||||
if (bytecode != Bytecodes::_invokedynamic) {
|
||||
GraphKit kit(jvms);
|
||||
Node* n = kit.argument(0);
|
||||
|
||||
|
@ -128,15 +129,16 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
|
|||
// Set the actually called method to have access to the class
|
||||
// and signature in the MethodHandleCompiler.
|
||||
method_handle->set_callee(call_method);
|
||||
method_handle->set_call_profile(&profile);
|
||||
|
||||
// Get an adapter for the MethodHandle.
|
||||
ciMethod* target_method = method_handle->get_method_handle_adapter();
|
||||
CallGenerator* hit_cg = NULL;
|
||||
if (target_method != NULL)
|
||||
hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor);
|
||||
if (target_method != NULL) {
|
||||
CallGenerator* hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor);
|
||||
if (hit_cg != NULL && hit_cg->is_inline())
|
||||
return hit_cg;
|
||||
}
|
||||
}
|
||||
|
||||
return CallGenerator::for_direct_call(call_method);
|
||||
}
|
||||
|
@ -151,16 +153,17 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
|
|||
// Set the actually called method to have access to the class
|
||||
// and signature in the MethodHandleCompiler.
|
||||
method_handle->set_callee(call_method);
|
||||
method_handle->set_call_profile(&profile);
|
||||
|
||||
// Get an adapter for the MethodHandle.
|
||||
ciMethod* target_method = method_handle->get_invokedynamic_adapter();
|
||||
CallGenerator* hit_cg = NULL;
|
||||
if (target_method != NULL)
|
||||
hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor);
|
||||
if (target_method != NULL) {
|
||||
CallGenerator* hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor);
|
||||
if (hit_cg != NULL && hit_cg->is_inline()) {
|
||||
CallGenerator* miss_cg = CallGenerator::for_dynamic_call(call_method);
|
||||
return CallGenerator::for_predicted_dynamic_call(method_handle, miss_cg, hit_cg, prof_factor);
|
||||
}
|
||||
}
|
||||
|
||||
// If something failed, generate a normal dynamic call.
|
||||
return CallGenerator::for_dynamic_call(call_method);
|
||||
|
|
|
@ -68,8 +68,8 @@ protected:
|
|||
JVMState* caller_jvms,
|
||||
int caller_bci);
|
||||
const char* try_to_inline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result);
|
||||
const char* shouldInline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result) const;
|
||||
const char* shouldNotInline(ciMethod* callee_method, ciMethod* caller_method, WarmCallInfo* wci_result) const;
|
||||
const char* should_inline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result) const;
|
||||
const char* should_not_inline(ciMethod* callee_method, ciMethod* caller_method, WarmCallInfo* wci_result) const;
|
||||
void print_inlining(ciMethod *callee_method, int caller_bci, const char *failure_msg) const;
|
||||
|
||||
InlineTree *caller_tree() const { return _caller_tree; }
|
||||
|
|
|
@ -616,9 +616,10 @@ int MethodHandleWalker::argument_count_slow() {
|
|||
// -----------------------------------------------------------------------------
|
||||
// MethodHandleCompiler
|
||||
|
||||
MethodHandleCompiler::MethodHandleCompiler(Handle root, methodHandle callee, bool is_invokedynamic, TRAPS)
|
||||
MethodHandleCompiler::MethodHandleCompiler(Handle root, methodHandle callee, int invoke_count, bool is_invokedynamic, TRAPS)
|
||||
: MethodHandleWalker(root, is_invokedynamic, THREAD),
|
||||
_callee(callee),
|
||||
_invoke_count(invoke_count),
|
||||
_thread(THREAD),
|
||||
_bytecode(THREAD, 50),
|
||||
_constants(THREAD, 10),
|
||||
|
@ -1182,7 +1183,7 @@ constantPoolHandle MethodHandleCompiler::get_constant_pool(TRAPS) const {
|
|||
|
||||
|
||||
methodHandle MethodHandleCompiler::get_method_oop(TRAPS) const {
|
||||
methodHandle nullHandle;
|
||||
methodHandle empty;
|
||||
// Create a method that holds the generated bytecode. invokedynamic
|
||||
// has no receiver, normal MH calls do.
|
||||
int flags_bits;
|
||||
|
@ -1191,13 +1192,16 @@ methodHandle MethodHandleCompiler::get_method_oop(TRAPS) const {
|
|||
else
|
||||
flags_bits = (/*JVM_MH_INVOKE_BITS |*/ JVM_ACC_PUBLIC | JVM_ACC_FINAL | JVM_ACC_SYNTHETIC);
|
||||
|
||||
// Create a new method
|
||||
methodHandle m;
|
||||
{
|
||||
methodOop m_oop = oopFactory::new_method(bytecode_length(),
|
||||
accessFlags_from(flags_bits),
|
||||
0, 0, 0, oopDesc::IsSafeConc, CHECK_(nullHandle));
|
||||
methodHandle m(THREAD, m_oop);
|
||||
m_oop = NULL; // oop not GC safe
|
||||
0, 0, 0, oopDesc::IsSafeConc, CHECK_(empty));
|
||||
m = methodHandle(THREAD, m_oop);
|
||||
}
|
||||
|
||||
constantPoolHandle cpool = get_constant_pool(CHECK_(nullHandle));
|
||||
constantPoolHandle cpool = get_constant_pool(CHECK_(empty));
|
||||
m->set_constants(cpool());
|
||||
|
||||
m->set_name_index(_name_index);
|
||||
|
@ -1212,16 +1216,32 @@ methodHandle MethodHandleCompiler::get_method_oop(TRAPS) const {
|
|||
typeArrayHandle exception_handlers(THREAD, Universe::the_empty_int_array());
|
||||
m->set_exception_table(exception_handlers());
|
||||
|
||||
// Set the carry bit of the invocation counter to force inlining of
|
||||
// the adapter.
|
||||
// Set the invocation counter's count to the invoke count of the
|
||||
// original call site.
|
||||
InvocationCounter* ic = m->invocation_counter();
|
||||
ic->set_carry_flag();
|
||||
ic->set(InvocationCounter::wait_for_compile, _invoke_count);
|
||||
|
||||
// Rewrite the method and set up the constant pool cache.
|
||||
objArrayOop m_array = oopFactory::new_system_objArray(1, CHECK_(nullHandle));
|
||||
objArrayOop m_array = oopFactory::new_system_objArray(1, CHECK_(empty));
|
||||
objArrayHandle methods(THREAD, m_array);
|
||||
methods->obj_at_put(0, m());
|
||||
Rewriter::rewrite(_target_klass(), cpool, methods, CHECK_(nullHandle)); // Use fake class.
|
||||
Rewriter::rewrite(_target_klass(), cpool, methods, CHECK_(empty)); // Use fake class.
|
||||
|
||||
// Create a new MDO
|
||||
{
|
||||
methodDataOop mdo = oopFactory::new_methodData(m, CHECK_(empty));
|
||||
assert(m->method_data() == NULL, "there should not be an MDO yet");
|
||||
m->set_method_data(mdo);
|
||||
|
||||
// Iterate over all profile data and set the count of the counter
|
||||
// data entries to the original call site counter.
|
||||
for (ProfileData* pd = mdo->first_data(); mdo->is_valid(pd); pd = mdo->next_data(pd)) {
|
||||
if (pd->is_CounterData()) {
|
||||
CounterData* cd = pd->as_CounterData();
|
||||
cd->set_count(_invoke_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (TraceMethodHandles) {
|
||||
|
|
|
@ -247,6 +247,7 @@ public:
|
|||
class MethodHandleCompiler : public MethodHandleWalker {
|
||||
private:
|
||||
methodHandle _callee;
|
||||
int _invoke_count; // count the original call site has been executed
|
||||
KlassHandle _rklass; // Return type for casting.
|
||||
BasicType _rtype;
|
||||
KlassHandle _target_klass;
|
||||
|
@ -416,7 +417,7 @@ private:
|
|||
methodHandle get_method_oop(TRAPS) const;
|
||||
|
||||
public:
|
||||
MethodHandleCompiler(Handle root, methodHandle call_method, bool for_invokedynamic, TRAPS);
|
||||
MethodHandleCompiler(Handle root, methodHandle call_method, int invoke_count, bool for_invokedynamic, TRAPS);
|
||||
|
||||
// Compile the given MH chain into bytecode.
|
||||
methodHandle compile(TRAPS);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue