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:
Christian Thalinger 2012-07-24 10:51:00 -07:00
parent 893817c28d
commit 12901d0e5b
181 changed files with 5760 additions and 14402 deletions

View file

@ -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;
}