mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-21 03:24:38 +02:00
7023639: JSR 292 method handle invocation needs a fast path for compiled code
6984705: JSR 292 method handle creation should not go through JNI Remove assembly code for JDK 7 chained method handles Co-authored-by: John Rose <john.r.rose@oracle.com> Co-authored-by: Michael Haupt <michael.haupt@oracle.com> Reviewed-by: jrose, twisti, kvn, mhaupt
This commit is contained in:
parent
893817c28d
commit
12901d0e5b
181 changed files with 5760 additions and 14402 deletions
|
@ -93,7 +93,7 @@ static bool is_init_with_ea(ciMethod* callee_method,
|
|||
);
|
||||
}
|
||||
|
||||
// positive filter: should send be inlined? returns NULL, if yes, or rejection msg
|
||||
// positive filter: should callee be inlined? returns NULL, if yes, or rejection msg
|
||||
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()) {
|
||||
|
@ -131,33 +131,6 @@ const char* InlineTree::should_inline(ciMethod* callee_method, ciMethod* caller_
|
|||
int call_site_count = method()->scale_count(profile.count());
|
||||
int invoke_count = method()->interpreter_invocation_count();
|
||||
|
||||
// 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();
|
||||
if (invoke_count == 0) {
|
||||
return "method handle not reached";
|
||||
}
|
||||
|
||||
if (_caller_jvms != NULL && _caller_jvms->method() != NULL &&
|
||||
_caller_jvms->method()->method_data() != NULL &&
|
||||
!_caller_jvms->method()->method_data()->is_empty()) {
|
||||
ciMethodData* mdo = _caller_jvms->method()->method_data();
|
||||
ciProfileData* mha_profile = mdo->bci_to_data(_caller_jvms->bci());
|
||||
assert(mha_profile, "must exist");
|
||||
CounterData* cd = mha_profile->as_CounterData();
|
||||
call_site_count = cd->count();
|
||||
} else {
|
||||
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;
|
||||
|
||||
|
@ -189,15 +162,16 @@ const char* InlineTree::should_inline(ciMethod* callee_method, ciMethod* caller_
|
|||
}
|
||||
|
||||
|
||||
// negative filter: should send NOT be inlined? returns NULL, ok to inline, or rejection msg
|
||||
// negative filter: should callee NOT be inlined? returns NULL, ok to inline, or rejection msg
|
||||
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;
|
||||
if (callee_method->is_abstract()) fail = "abstract method";
|
||||
if ( callee_method->is_abstract()) fail = "abstract method";
|
||||
// note: we allow ik->is_abstract()
|
||||
if (!callee_method->holder()->is_initialized()) fail = "method holder not initialized";
|
||||
if (callee_method->is_native()) fail = "native method";
|
||||
if (!callee_method->holder()->is_initialized()) fail = "method holder not initialized";
|
||||
if ( callee_method->is_native()) fail = "native method";
|
||||
if ( callee_method->dont_inline()) fail = "don't inline by annotation";
|
||||
|
||||
if (fail) {
|
||||
*wci_result = *(WarmCallInfo::always_cold());
|
||||
|
@ -217,7 +191,8 @@ const char* InlineTree::should_not_inline(ciMethod *callee_method, ciMethod* cal
|
|||
}
|
||||
}
|
||||
|
||||
if (callee_method->has_compiled_code() && callee_method->instructions_size(CompLevel_full_optimization) > InlineSmallCode) {
|
||||
if (callee_method->has_compiled_code() &&
|
||||
callee_method->instructions_size(CompLevel_full_optimization) > InlineSmallCode) {
|
||||
wci_result->set_profit(wci_result->profit() * 0.1);
|
||||
// %%% adjust wci_result->size()?
|
||||
}
|
||||
|
@ -225,26 +200,25 @@ const char* InlineTree::should_not_inline(ciMethod *callee_method, ciMethod* cal
|
|||
return NULL;
|
||||
}
|
||||
|
||||
// Always inline MethodHandle methods and generated MethodHandle adapters.
|
||||
if (callee_method->is_method_handle_invoke() || callee_method->is_method_handle_adapter())
|
||||
return NULL;
|
||||
|
||||
// First check all inlining restrictions which are required for correctness
|
||||
if (callee_method->is_abstract()) return "abstract method";
|
||||
if ( callee_method->is_abstract()) return "abstract method";
|
||||
// note: we allow ik->is_abstract()
|
||||
if (!callee_method->holder()->is_initialized()) return "method holder not initialized";
|
||||
if (callee_method->is_native()) return "native method";
|
||||
if (callee_method->has_unloaded_classes_in_signature()) return "unloaded signature classes";
|
||||
if (!callee_method->holder()->is_initialized()) return "method holder not initialized";
|
||||
if ( callee_method->is_native()) return "native method";
|
||||
if ( callee_method->dont_inline()) return "don't inline by annotation";
|
||||
if ( callee_method->has_unloaded_classes_in_signature()) return "unloaded signature classes";
|
||||
|
||||
if (callee_method->should_inline()) {
|
||||
if (callee_method->force_inline() || callee_method->should_inline()) {
|
||||
// ignore heuristic controls on inlining
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Now perform checks which are heuristic
|
||||
|
||||
if( callee_method->has_compiled_code() && callee_method->instructions_size(CompLevel_full_optimization) > InlineSmallCode )
|
||||
if (callee_method->has_compiled_code() &&
|
||||
callee_method->instructions_size(CompLevel_full_optimization) > InlineSmallCode) {
|
||||
return "already compiled into a big method";
|
||||
}
|
||||
|
||||
// don't inline exception code unless the top method belongs to an
|
||||
// exception class
|
||||
|
@ -270,7 +244,7 @@ const char* InlineTree::should_not_inline(ciMethod *callee_method, ciMethod* cal
|
|||
}
|
||||
|
||||
// use frequency-based objections only for non-trivial methods
|
||||
if (callee_method->code_size_for_inlining() <= MaxTrivialSize) return NULL;
|
||||
if (callee_method->code_size() <= MaxTrivialSize) return NULL;
|
||||
|
||||
// don't use counts with -Xcomp or CTW
|
||||
if (UseInterpreter && !CompileTheWorld) {
|
||||
|
@ -319,7 +293,7 @@ const char* InlineTree::try_to_inline(ciMethod* callee_method, ciMethod* caller_
|
|||
}
|
||||
|
||||
// suppress a few checks for accessors and trivial methods
|
||||
if (callee_method->code_size_for_inlining() > MaxTrivialSize) {
|
||||
if (callee_method->code_size() > MaxTrivialSize) {
|
||||
|
||||
// don't inline into giant methods
|
||||
if (C->unique() > (uint)NodeCountInliningCutoff) {
|
||||
|
@ -346,7 +320,7 @@ const char* InlineTree::try_to_inline(ciMethod* callee_method, ciMethod* caller_
|
|||
}
|
||||
|
||||
// detect direct and indirect recursive inlining
|
||||
{
|
||||
if (!callee_method->is_compiled_lambda_form()) {
|
||||
// count the current method and the callee
|
||||
int inline_level = (method() == callee_method) ? 1 : 0;
|
||||
if (inline_level > MaxRecursiveInlineLevel)
|
||||
|
@ -412,6 +386,7 @@ bool pass_initial_checks(ciMethod* caller_method, int caller_bci, ciMethod* call
|
|||
const char* InlineTree::check_can_parse(ciMethod* callee) {
|
||||
// Certain methods cannot be parsed at all:
|
||||
if ( callee->is_native()) return "native method";
|
||||
if ( callee->is_abstract()) return "abstract method";
|
||||
if (!callee->can_be_compiled()) return "not compilable (disabled)";
|
||||
if (!callee->has_balanced_monitors()) return "not compilable (unbalanced monitors)";
|
||||
if ( callee->get_flow_analysis()->failing()) return "not compilable (flow analysis failed)";
|
||||
|
@ -426,7 +401,7 @@ void InlineTree::print_inlining(ciMethod* callee_method, int caller_bci, const c
|
|||
if (Verbose && callee_method) {
|
||||
const InlineTree *top = this;
|
||||
while( top->caller_tree() != NULL ) { top = top->caller_tree(); }
|
||||
tty->print(" bcs: %d+%d invoked: %d", top->count_inline_bcs(), callee_method->code_size(), callee_method->interpreter_invocation_count());
|
||||
//tty->print(" bcs: %d+%d invoked: %d", top->count_inline_bcs(), callee_method->code_size(), callee_method->interpreter_invocation_count());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -449,10 +424,7 @@ WarmCallInfo* InlineTree::ok_to_inline(ciMethod* callee_method, JVMState* jvms,
|
|||
|
||||
// Do some initial checks.
|
||||
if (!pass_initial_checks(caller_method, caller_bci, callee_method)) {
|
||||
if (PrintInlining) {
|
||||
failure_msg = "failed_initial_checks";
|
||||
print_inlining(callee_method, caller_bci, failure_msg);
|
||||
}
|
||||
if (PrintInlining) print_inlining(callee_method, caller_bci, "failed initial checks");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -539,9 +511,10 @@ InlineTree *InlineTree::build_inline_tree_for_callee( ciMethod* callee_method, J
|
|||
}
|
||||
int max_inline_level_adjust = 0;
|
||||
if (caller_jvms->method() != NULL) {
|
||||
if (caller_jvms->method()->is_method_handle_adapter())
|
||||
if (caller_jvms->method()->is_compiled_lambda_form())
|
||||
max_inline_level_adjust += 1; // don't count actions in MH or indy adapter frames
|
||||
else if (callee_method->is_method_handle_invoke()) {
|
||||
else if (callee_method->is_method_handle_intrinsic() ||
|
||||
callee_method->is_compiled_lambda_form()) {
|
||||
max_inline_level_adjust += 1; // don't count method handle calls from java.lang.invoke implem
|
||||
}
|
||||
if (max_inline_level_adjust != 0 && PrintInlining && (Verbose || WizardMode)) {
|
||||
|
@ -590,7 +563,7 @@ InlineTree *InlineTree::build_inline_tree_root() {
|
|||
// Given a jvms, which determines a call chain from the root method,
|
||||
// find the corresponding inline tree.
|
||||
// Note: This method will be removed or replaced as InlineTree goes away.
|
||||
InlineTree* InlineTree::find_subtree_from_root(InlineTree* root, JVMState* jvms, ciMethod* callee, bool create_if_not_found) {
|
||||
InlineTree* InlineTree::find_subtree_from_root(InlineTree* root, JVMState* jvms, ciMethod* callee) {
|
||||
InlineTree* iltp = root;
|
||||
uint depth = jvms && jvms->has_method() ? jvms->depth() : 0;
|
||||
for (uint d = 1; d <= depth; d++) {
|
||||
|
@ -599,12 +572,12 @@ InlineTree* InlineTree::find_subtree_from_root(InlineTree* root, JVMState* jvms,
|
|||
assert(jvmsp->method() == iltp->method(), "tree still in sync");
|
||||
ciMethod* d_callee = (d == depth) ? callee : jvms->of_depth(d+1)->method();
|
||||
InlineTree* sub = iltp->callee_at(jvmsp->bci(), d_callee);
|
||||
if (!sub) {
|
||||
if (create_if_not_found && d == depth) {
|
||||
return iltp->build_inline_tree_for_callee(d_callee, jvmsp, jvmsp->bci());
|
||||
if (sub == NULL) {
|
||||
if (d == depth) {
|
||||
sub = iltp->build_inline_tree_for_callee(d_callee, jvmsp, jvmsp->bci());
|
||||
}
|
||||
assert(sub != NULL, "should be a sub-ilt here");
|
||||
return NULL;
|
||||
guarantee(sub != NULL, "should be a sub-ilt here");
|
||||
return sub;
|
||||
}
|
||||
iltp = sub;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue