提交 5e0d3f26 编写于 作者: T twisti

8005418: JSR 292: virtual dispatch bug in 292 impl

Reviewed-by: jrose, kvn
上级 d1681e4e
...@@ -717,6 +717,7 @@ CallGenerator* CallGenerator::for_method_handle_call(JVMState* jvms, ciMethod* c ...@@ -717,6 +717,7 @@ CallGenerator* CallGenerator::for_method_handle_call(JVMState* jvms, ciMethod* c
(input_not_const || !C->inlining_incrementally() || C->over_inlining_cutoff())) { (input_not_const || !C->inlining_incrementally() || C->over_inlining_cutoff())) {
return CallGenerator::for_mh_late_inline(caller, callee, input_not_const); return CallGenerator::for_mh_late_inline(caller, callee, input_not_const);
} else { } else {
// Out-of-line call.
return CallGenerator::for_direct_call(callee); return CallGenerator::for_direct_call(callee);
} }
} }
...@@ -739,7 +740,7 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod* ...@@ -739,7 +740,7 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod*
guarantee(!target->is_method_handle_intrinsic(), "should not happen"); // XXX remove guarantee(!target->is_method_handle_intrinsic(), "should not happen"); // XXX remove
const int vtable_index = Method::invalid_vtable_index; const int vtable_index = Method::invalid_vtable_index;
CallGenerator* cg = C->call_generator(target, vtable_index, false, jvms, true, PROB_ALWAYS, true, true); CallGenerator* cg = C->call_generator(target, vtable_index, false, jvms, true, PROB_ALWAYS, true, true);
assert (!cg->is_late_inline() || cg->is_mh_late_inline(), "no late inline here"); assert(!cg->is_late_inline() || cg->is_mh_late_inline(), "no late inline here");
if (cg != NULL && cg->is_inline()) if (cg != NULL && cg->is_inline())
return cg; return cg;
} }
...@@ -787,10 +788,25 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod* ...@@ -787,10 +788,25 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod*
} }
} }
} }
const int vtable_index = Method::invalid_vtable_index;
const bool call_is_virtual = target->is_abstract(); // FIXME workaround // Try to get the most accurate receiver type
CallGenerator* cg = C->call_generator(target, vtable_index, call_is_virtual, jvms, true, PROB_ALWAYS, true, true); const bool is_virtual = (iid == vmIntrinsics::_linkToVirtual);
assert (!cg->is_late_inline() || cg->is_mh_late_inline(), "no late inline here"); const bool is_virtual_or_interface = (is_virtual || iid == vmIntrinsics::_linkToInterface);
int vtable_index = Method::invalid_vtable_index;
bool call_does_dispatch = false;
if (is_virtual_or_interface) {
ciInstanceKlass* klass = target->holder();
Node* receiver_node = kit.argument(0);
const TypeOopPtr* receiver_type = gvn.type(receiver_node)->isa_oopptr();
// call_does_dispatch and vtable_index are out-parameters. They might be changed.
target = C->optimize_virtual_call(caller, jvms->bci(), klass, target, receiver_type,
is_virtual,
call_does_dispatch, vtable_index); // out-parameters
}
CallGenerator* cg = C->call_generator(target, vtable_index, call_does_dispatch, jvms, true, PROB_ALWAYS, true, true);
assert(!cg->is_late_inline() || cg->is_mh_late_inline(), "no late inline here");
if (cg != NULL && cg->is_inline()) if (cg != NULL && cg->is_inline())
return cg; return cg;
} }
......
...@@ -72,6 +72,7 @@ class SafePointNode; ...@@ -72,6 +72,7 @@ class SafePointNode;
class JVMState; class JVMState;
class TypeData; class TypeData;
class TypePtr; class TypePtr;
class TypeOopPtr;
class TypeFunc; class TypeFunc;
class Unique_Node_List; class Unique_Node_List;
class nmethod; class nmethod;
...@@ -740,9 +741,17 @@ class Compile : public Phase { ...@@ -740,9 +741,17 @@ class Compile : public Phase {
// Decide how to build a call. // Decide how to build a call.
// The profile factor is a discount to apply to this site's interp. profile. // The profile factor is a discount to apply to this site's interp. profile.
CallGenerator* call_generator(ciMethod* call_method, int vtable_index, bool call_is_virtual, JVMState* jvms, bool allow_inline, float profile_factor, bool allow_intrinsics = true, bool delayed_forbidden = false); CallGenerator* call_generator(ciMethod* call_method, int vtable_index, bool call_does_dispatch, JVMState* jvms, bool allow_inline, float profile_factor, bool allow_intrinsics = true, bool delayed_forbidden = false);
bool should_delay_inlining(ciMethod* call_method, JVMState* jvms); bool should_delay_inlining(ciMethod* call_method, JVMState* jvms);
// Helper functions to identify inlining potential at call-site
ciMethod* optimize_virtual_call(ciMethod* caller, int bci, ciInstanceKlass* klass,
ciMethod* callee, const TypeOopPtr* receiver_type,
bool is_virtual,
bool &call_does_dispatch, int &vtable_index);
ciMethod* optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass* klass,
ciMethod* callee, const TypeOopPtr* receiver_type);
// Report if there were too many traps at a current method and bci. // Report if there were too many traps at a current method and bci.
// Report if a trap was recorded, and/or PerMethodTrapLimit was exceeded. // Report if a trap was recorded, and/or PerMethodTrapLimit was exceeded.
// If there is no MDO at all, report no trap unless told to assume it. // If there is no MDO at all, report no trap unless told to assume it.
......
...@@ -61,7 +61,7 @@ void trace_type_profile(Compile* C, ciMethod *method, int depth, int bci, ciMeth ...@@ -61,7 +61,7 @@ void trace_type_profile(Compile* C, ciMethod *method, int depth, int bci, ciMeth
} }
} }
CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool call_is_virtual, CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool call_does_dispatch,
JVMState* jvms, bool allow_inline, JVMState* jvms, bool allow_inline,
float prof_factor, bool allow_intrinsics, bool delayed_forbidden) { float prof_factor, bool allow_intrinsics, bool delayed_forbidden) {
ciMethod* caller = jvms->method(); ciMethod* caller = jvms->method();
...@@ -82,7 +82,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool ...@@ -82,7 +82,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool
// See how many times this site has been invoked. // See how many times this site has been invoked.
int site_count = profile.count(); int site_count = profile.count();
int receiver_count = -1; int receiver_count = -1;
if (call_is_virtual && UseTypeProfile && profile.has_receiver(0)) { if (call_does_dispatch && UseTypeProfile && profile.has_receiver(0)) {
// Receivers in the profile structure are ordered by call counts // Receivers in the profile structure are ordered by call counts
// so that the most called (major) receiver is profile.receiver(0). // so that the most called (major) receiver is profile.receiver(0).
receiver_count = profile.receiver_count(0); receiver_count = profile.receiver_count(0);
...@@ -94,7 +94,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool ...@@ -94,7 +94,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool
int r2id = (rid != -1 && profile.has_receiver(1))? log->identify(profile.receiver(1)):-1; int r2id = (rid != -1 && profile.has_receiver(1))? log->identify(profile.receiver(1)):-1;
log->begin_elem("call method='%d' count='%d' prof_factor='%g'", log->begin_elem("call method='%d' count='%d' prof_factor='%g'",
log->identify(callee), site_count, prof_factor); log->identify(callee), site_count, prof_factor);
if (call_is_virtual) log->print(" virtual='1'"); if (call_does_dispatch) log->print(" virtual='1'");
if (allow_inline) log->print(" inline='1'"); if (allow_inline) log->print(" inline='1'");
if (receiver_count >= 0) { if (receiver_count >= 0) {
log->print(" receiver='%d' receiver_count='%d'", rid, receiver_count); log->print(" receiver='%d' receiver_count='%d'", rid, receiver_count);
...@@ -111,12 +111,12 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool ...@@ -111,12 +111,12 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool
// We do this before the strict f.p. check below because the // We do this before the strict f.p. check below because the
// intrinsics handle strict f.p. correctly. // intrinsics handle strict f.p. correctly.
if (allow_inline && allow_intrinsics) { if (allow_inline && allow_intrinsics) {
CallGenerator* cg = find_intrinsic(callee, call_is_virtual); CallGenerator* cg = find_intrinsic(callee, call_does_dispatch);
if (cg != NULL) { if (cg != NULL) {
if (cg->is_predicted()) { if (cg->is_predicted()) {
// Code without intrinsic but, hopefully, inlined. // Code without intrinsic but, hopefully, inlined.
CallGenerator* inline_cg = this->call_generator(callee, CallGenerator* inline_cg = this->call_generator(callee,
vtable_index, call_is_virtual, jvms, allow_inline, prof_factor, false); vtable_index, call_does_dispatch, jvms, allow_inline, prof_factor, false);
if (inline_cg != NULL) { if (inline_cg != NULL) {
cg = CallGenerator::for_predicted_intrinsic(cg, inline_cg); cg = CallGenerator::for_predicted_intrinsic(cg, inline_cg);
} }
...@@ -131,7 +131,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool ...@@ -131,7 +131,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool
// have bytecodes and so normal inlining fails. // have bytecodes and so normal inlining fails.
if (callee->is_method_handle_intrinsic()) { if (callee->is_method_handle_intrinsic()) {
CallGenerator* cg = CallGenerator::for_method_handle_call(jvms, caller, callee, delayed_forbidden); CallGenerator* cg = CallGenerator::for_method_handle_call(jvms, caller, callee, delayed_forbidden);
assert (cg == NULL || !delayed_forbidden || !cg->is_late_inline() || cg->is_mh_late_inline(), "unexpected CallGenerator"); assert(cg == NULL || !delayed_forbidden || !cg->is_late_inline() || cg->is_mh_late_inline(), "unexpected CallGenerator");
return cg; return cg;
} }
...@@ -149,7 +149,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool ...@@ -149,7 +149,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool
float expected_uses = past_uses; float expected_uses = past_uses;
// Try inlining a bytecoded method: // Try inlining a bytecoded method:
if (!call_is_virtual) { if (!call_does_dispatch) {
InlineTree* ilt; InlineTree* ilt;
if (UseOldInlining) { if (UseOldInlining) {
ilt = InlineTree::find_subtree_from_root(this->ilt(), jvms->caller(), jvms->method()); ilt = InlineTree::find_subtree_from_root(this->ilt(), jvms->caller(), jvms->method());
...@@ -188,14 +188,14 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool ...@@ -188,14 +188,14 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool
} else if (require_inline || !InlineWarmCalls) { } else if (require_inline || !InlineWarmCalls) {
return cg; return cg;
} else { } else {
CallGenerator* cold_cg = call_generator(callee, vtable_index, call_is_virtual, jvms, false, prof_factor); CallGenerator* cold_cg = call_generator(callee, vtable_index, call_does_dispatch, jvms, false, prof_factor);
return CallGenerator::for_warm_call(ci, cold_cg, cg); return CallGenerator::for_warm_call(ci, cold_cg, cg);
} }
} }
} }
// Try using the type profile. // Try using the type profile.
if (call_is_virtual && site_count > 0 && receiver_count > 0) { if (call_does_dispatch && site_count > 0 && receiver_count > 0) {
// The major receiver's count >= TypeProfileMajorReceiverPercent of site_count. // The major receiver's count >= TypeProfileMajorReceiverPercent of site_count.
bool have_major_receiver = (100.*profile.receiver_prob(0) >= (float)TypeProfileMajorReceiverPercent); bool have_major_receiver = (100.*profile.receiver_prob(0) >= (float)TypeProfileMajorReceiverPercent);
ciMethod* receiver_method = NULL; ciMethod* receiver_method = NULL;
...@@ -209,7 +209,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool ...@@ -209,7 +209,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool
if (receiver_method != NULL) { if (receiver_method != NULL) {
// The single majority receiver sufficiently outweighs the minority. // The single majority receiver sufficiently outweighs the minority.
CallGenerator* hit_cg = this->call_generator(receiver_method, CallGenerator* hit_cg = this->call_generator(receiver_method,
vtable_index, !call_is_virtual, jvms, allow_inline, prof_factor); vtable_index, !call_does_dispatch, jvms, allow_inline, prof_factor);
if (hit_cg != NULL) { if (hit_cg != NULL) {
// Look up second receiver. // Look up second receiver.
CallGenerator* next_hit_cg = NULL; CallGenerator* next_hit_cg = NULL;
...@@ -219,7 +219,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool ...@@ -219,7 +219,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool
profile.receiver(1)); profile.receiver(1));
if (next_receiver_method != NULL) { if (next_receiver_method != NULL) {
next_hit_cg = this->call_generator(next_receiver_method, next_hit_cg = this->call_generator(next_receiver_method,
vtable_index, !call_is_virtual, jvms, vtable_index, !call_does_dispatch, jvms,
allow_inline, prof_factor); allow_inline, prof_factor);
if (next_hit_cg != NULL && !next_hit_cg->is_inline() && if (next_hit_cg != NULL && !next_hit_cg->is_inline() &&
have_major_receiver && UseOnlyInlinedBimorphic) { have_major_receiver && UseOnlyInlinedBimorphic) {
...@@ -265,7 +265,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool ...@@ -265,7 +265,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool
// There was no special inlining tactic, or it bailed out. // There was no special inlining tactic, or it bailed out.
// Use a more generic tactic, like a simple call. // Use a more generic tactic, like a simple call.
if (call_is_virtual) { if (call_does_dispatch) {
return CallGenerator::for_virtual_call(callee, vtable_index); return CallGenerator::for_virtual_call(callee, vtable_index);
} else { } else {
// Class Hierarchy Analysis or Type Profile reveals a unique target, // Class Hierarchy Analysis or Type Profile reveals a unique target,
...@@ -397,6 +397,7 @@ void Parse::do_call() { ...@@ -397,6 +397,7 @@ void Parse::do_call() {
// orig_callee is the resolved callee which's signature includes the // orig_callee is the resolved callee which's signature includes the
// appendix argument. // appendix argument.
const int nargs = orig_callee->arg_size(); const int nargs = orig_callee->arg_size();
const bool is_signature_polymorphic = MethodHandles::is_signature_polymorphic(orig_callee->intrinsic_id());
// Push appendix argument (MethodType, CallSite, etc.), if one. // Push appendix argument (MethodType, CallSite, etc.), if one.
if (iter().has_appendix()) { if (iter().has_appendix()) {
...@@ -413,25 +414,18 @@ void Parse::do_call() { ...@@ -413,25 +414,18 @@ void Parse::do_call() {
// Then we may introduce a run-time check and inline on the path where it succeeds. // Then we may introduce a run-time check and inline on the path where it succeeds.
// The other path may uncommon_trap, check for another receiver, or do a v-call. // The other path may uncommon_trap, check for another receiver, or do a v-call.
// Choose call strategy.
bool call_is_virtual = is_virtual_or_interface;
int vtable_index = Method::invalid_vtable_index;
ciMethod* callee = orig_callee;
// Try to get the most accurate receiver type // Try to get the most accurate receiver type
ciMethod* callee = orig_callee;
int vtable_index = Method::invalid_vtable_index;
bool call_does_dispatch = false;
if (is_virtual_or_interface) { if (is_virtual_or_interface) {
Node* receiver_node = stack(sp() - nargs); Node* receiver_node = stack(sp() - nargs);
const TypeOopPtr* receiver_type = _gvn.type(receiver_node)->isa_oopptr(); const TypeOopPtr* receiver_type = _gvn.type(receiver_node)->isa_oopptr();
ciMethod* optimized_virtual_method = optimize_inlining(method(), bci(), klass, orig_callee, receiver_type); // call_does_dispatch and vtable_index are out-parameters. They might be changed.
callee = C->optimize_virtual_call(method(), bci(), klass, orig_callee, receiver_type,
// Have the call been sufficiently improved such that it is no longer a virtual? is_virtual,
if (optimized_virtual_method != NULL) { call_does_dispatch, vtable_index); // out-parameters
callee = optimized_virtual_method;
call_is_virtual = false;
} else if (!UseInlineCaches && is_virtual && callee->is_loaded()) {
// We can make a vtable call at this site
vtable_index = callee->resolve_vtable_index(method()->holder(), klass);
}
} }
// Note: It's OK to try to inline a virtual call. // Note: It's OK to try to inline a virtual call.
...@@ -447,7 +441,7 @@ void Parse::do_call() { ...@@ -447,7 +441,7 @@ void Parse::do_call() {
// Decide call tactic. // Decide call tactic.
// This call checks with CHA, the interpreter profile, intrinsics table, etc. // This call checks with CHA, the interpreter profile, intrinsics table, etc.
// It decides whether inlining is desirable or not. // It decides whether inlining is desirable or not.
CallGenerator* cg = C->call_generator(callee, vtable_index, call_is_virtual, jvms, try_inline, prof_factor()); CallGenerator* cg = C->call_generator(callee, vtable_index, call_does_dispatch, jvms, try_inline, prof_factor());
// NOTE: Don't use orig_callee and callee after this point! Use cg->method() instead. // NOTE: Don't use orig_callee and callee after this point! Use cg->method() instead.
orig_callee = callee = NULL; orig_callee = callee = NULL;
...@@ -487,7 +481,7 @@ void Parse::do_call() { ...@@ -487,7 +481,7 @@ void Parse::do_call() {
// the call site, perhaps because it did not match a pattern the // the call site, perhaps because it did not match a pattern the
// intrinsic was expecting to optimize. Should always be possible to // intrinsic was expecting to optimize. Should always be possible to
// get a normal java call that may inline in that case // get a normal java call that may inline in that case
cg = C->call_generator(cg->method(), vtable_index, call_is_virtual, jvms, try_inline, prof_factor(), /* allow_intrinsics= */ false); cg = C->call_generator(cg->method(), vtable_index, call_does_dispatch, jvms, try_inline, prof_factor(), /* allow_intrinsics= */ false);
if ((new_jvms = cg->generate(jvms)) == NULL) { if ((new_jvms = cg->generate(jvms)) == NULL) {
guarantee(failing(), "call failed to generate: calls should work"); guarantee(failing(), "call failed to generate: calls should work");
return; return;
...@@ -522,55 +516,44 @@ void Parse::do_call() { ...@@ -522,55 +516,44 @@ void Parse::do_call() {
round_double_result(cg->method()); round_double_result(cg->method());
ciType* rtype = cg->method()->return_type(); ciType* rtype = cg->method()->return_type();
if (Bytecodes::has_optional_appendix(iter().cur_bc_raw())) { ciType* ctype = declared_signature->return_type();
if (Bytecodes::has_optional_appendix(iter().cur_bc_raw()) || is_signature_polymorphic) {
// Be careful here with return types. // Be careful here with return types.
ciType* ctype = declared_signature->return_type();
if (ctype != rtype) { if (ctype != rtype) {
BasicType rt = rtype->basic_type(); BasicType rt = rtype->basic_type();
BasicType ct = ctype->basic_type(); BasicType ct = ctype->basic_type();
Node* retnode = peek();
if (ct == T_VOID) { if (ct == T_VOID) {
// It's OK for a method to return a value that is discarded. // It's OK for a method to return a value that is discarded.
// The discarding does not require any special action from the caller. // The discarding does not require any special action from the caller.
// The Java code knows this, at VerifyType.isNullConversion. // The Java code knows this, at VerifyType.isNullConversion.
pop_node(rt); // whatever it was, pop it pop_node(rt); // whatever it was, pop it
retnode = top();
} else if (rt == T_INT || is_subword_type(rt)) { } else if (rt == T_INT || is_subword_type(rt)) {
// FIXME: This logic should be factored out. // Nothing. These cases are handled in lambda form bytecode.
if (ct == T_BOOLEAN) { assert(ct == T_INT || is_subword_type(ct), err_msg_res("must match: rt=%s, ct=%s", type2name(rt), type2name(ct)));
retnode = _gvn.transform( new (C) AndINode(retnode, intcon(0x1)) );
} else if (ct == T_CHAR) {
retnode = _gvn.transform( new (C) AndINode(retnode, intcon(0xFFFF)) );
} else if (ct == T_BYTE) {
retnode = _gvn.transform( new (C) LShiftINode(retnode, intcon(24)) );
retnode = _gvn.transform( new (C) RShiftINode(retnode, intcon(24)) );
} else if (ct == T_SHORT) {
retnode = _gvn.transform( new (C) LShiftINode(retnode, intcon(16)) );
retnode = _gvn.transform( new (C) RShiftINode(retnode, intcon(16)) );
} else {
assert(ct == T_INT, err_msg_res("rt=%s, ct=%s", type2name(rt), type2name(ct)));
}
} else if (rt == T_OBJECT || rt == T_ARRAY) { } else if (rt == T_OBJECT || rt == T_ARRAY) {
assert(ct == T_OBJECT || ct == T_ARRAY, err_msg_res("rt=%s, ct=%s", type2name(rt), type2name(ct))); assert(ct == T_OBJECT || ct == T_ARRAY, err_msg_res("rt=%s, ct=%s", type2name(rt), type2name(ct)));
if (ctype->is_loaded()) { if (ctype->is_loaded()) {
const TypeOopPtr* arg_type = TypeOopPtr::make_from_klass(rtype->as_klass()); const TypeOopPtr* arg_type = TypeOopPtr::make_from_klass(rtype->as_klass());
const Type* sig_type = TypeOopPtr::make_from_klass(ctype->as_klass()); const Type* sig_type = TypeOopPtr::make_from_klass(ctype->as_klass());
if (arg_type != NULL && !arg_type->higher_equal(sig_type)) { if (arg_type != NULL && !arg_type->higher_equal(sig_type)) {
Node* retnode = pop();
Node* cast_obj = _gvn.transform(new (C) CheckCastPPNode(control(), retnode, sig_type)); Node* cast_obj = _gvn.transform(new (C) CheckCastPPNode(control(), retnode, sig_type));
pop();
push(cast_obj); push(cast_obj);
} }
} }
} else { } else {
assert(ct == rt, err_msg("unexpected mismatch rt=%d, ct=%d", rt, ct)); assert(rt == ct, err_msg_res("unexpected mismatch: rt=%s, ct=%s", type2name(rt), type2name(ct)));
// push a zero; it's better than getting an oop/int mismatch // push a zero; it's better than getting an oop/int mismatch
retnode = pop_node(rt); pop_node(rt);
retnode = zerocon(ct); Node* retnode = zerocon(ct);
push_node(ct, retnode); push_node(ct, retnode);
} }
// Now that the value is well-behaved, continue with the call-site type. // Now that the value is well-behaved, continue with the call-site type.
rtype = ctype; rtype = ctype;
} }
} else {
assert(rtype == ctype, "mismatched return types"); // symbolic resolution enforces this
} }
// If the return type of the method is not loaded, assert that the // If the return type of the method is not loaded, assert that the
...@@ -888,17 +871,39 @@ void Parse::count_compiled_calls(bool at_method_entry, bool is_inline) { ...@@ -888,17 +871,39 @@ void Parse::count_compiled_calls(bool at_method_entry, bool is_inline) {
#endif //PRODUCT #endif //PRODUCT
ciMethod* Compile::optimize_virtual_call(ciMethod* caller, int bci, ciInstanceKlass* klass,
ciMethod* callee, const TypeOopPtr* receiver_type,
bool is_virtual,
bool& call_does_dispatch, int& vtable_index) {
// Set default values for out-parameters.
call_does_dispatch = true;
vtable_index = Method::invalid_vtable_index;
// Choose call strategy.
ciMethod* optimized_virtual_method = optimize_inlining(caller, bci, klass, callee, receiver_type);
// Have the call been sufficiently improved such that it is no longer a virtual?
if (optimized_virtual_method != NULL) {
callee = optimized_virtual_method;
call_does_dispatch = false;
} else if (!UseInlineCaches && is_virtual && callee->is_loaded()) {
// We can make a vtable call at this site
vtable_index = callee->resolve_vtable_index(caller->holder(), klass);
}
return callee;
}
// Identify possible target method and inlining style // Identify possible target method and inlining style
ciMethod* Parse::optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass* klass, ciMethod* Compile::optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass* klass,
ciMethod *dest_method, const TypeOopPtr* receiver_type) { ciMethod* callee, const TypeOopPtr* receiver_type) {
// only use for virtual or interface calls // only use for virtual or interface calls
// If it is obviously final, do not bother to call find_monomorphic_target, // If it is obviously final, do not bother to call find_monomorphic_target,
// because the class hierarchy checks are not needed, and may fail due to // because the class hierarchy checks are not needed, and may fail due to
// incompletely loaded classes. Since we do our own class loading checks // incompletely loaded classes. Since we do our own class loading checks
// in this module, we may confidently bind to any method. // in this module, we may confidently bind to any method.
if (dest_method->can_be_statically_bound()) { if (callee->can_be_statically_bound()) {
return dest_method; return callee;
} }
// Attempt to improve the receiver // Attempt to improve the receiver
...@@ -907,8 +912,8 @@ ciMethod* Parse::optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass* k ...@@ -907,8 +912,8 @@ ciMethod* Parse::optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass* k
if (receiver_type != NULL) { if (receiver_type != NULL) {
// Array methods are all inherited from Object, and are monomorphic. // Array methods are all inherited from Object, and are monomorphic.
if (receiver_type->isa_aryptr() && if (receiver_type->isa_aryptr() &&
dest_method->holder() == env()->Object_klass()) { callee->holder() == env()->Object_klass()) {
return dest_method; return callee;
} }
// All other interesting cases are instance klasses. // All other interesting cases are instance klasses.
...@@ -928,7 +933,7 @@ ciMethod* Parse::optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass* k ...@@ -928,7 +933,7 @@ ciMethod* Parse::optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass* k
} }
ciInstanceKlass* calling_klass = caller->holder(); ciInstanceKlass* calling_klass = caller->holder();
ciMethod* cha_monomorphic_target = dest_method->find_monomorphic_target(calling_klass, klass, actual_receiver); ciMethod* cha_monomorphic_target = callee->find_monomorphic_target(calling_klass, klass, actual_receiver);
if (cha_monomorphic_target != NULL) { if (cha_monomorphic_target != NULL) {
assert(!cha_monomorphic_target->is_abstract(), ""); assert(!cha_monomorphic_target->is_abstract(), "");
// Look at the method-receiver type. Does it add "too much information"? // Look at the method-receiver type. Does it add "too much information"?
...@@ -946,10 +951,10 @@ ciMethod* Parse::optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass* k ...@@ -946,10 +951,10 @@ ciMethod* Parse::optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass* k
cha_monomorphic_target->print(); cha_monomorphic_target->print();
tty->cr(); tty->cr();
} }
if (C->log() != NULL) { if (log() != NULL) {
C->log()->elem("missed_CHA_opportunity klass='%d' method='%d'", log()->elem("missed_CHA_opportunity klass='%d' method='%d'",
C->log()->identify(klass), log()->identify(klass),
C->log()->identify(cha_monomorphic_target)); log()->identify(cha_monomorphic_target));
} }
cha_monomorphic_target = NULL; cha_monomorphic_target = NULL;
} }
...@@ -961,7 +966,7 @@ ciMethod* Parse::optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass* k ...@@ -961,7 +966,7 @@ ciMethod* Parse::optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass* k
// by dynamic class loading. Be sure to test the "static" receiver // by dynamic class loading. Be sure to test the "static" receiver
// dest_method here, as opposed to the actual receiver, which may // dest_method here, as opposed to the actual receiver, which may
// falsely lead us to believe that the receiver is final or private. // falsely lead us to believe that the receiver is final or private.
C->dependencies()->assert_unique_concrete_method(actual_receiver, cha_monomorphic_target); dependencies()->assert_unique_concrete_method(actual_receiver, cha_monomorphic_target);
return cha_monomorphic_target; return cha_monomorphic_target;
} }
...@@ -970,7 +975,7 @@ ciMethod* Parse::optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass* k ...@@ -970,7 +975,7 @@ ciMethod* Parse::optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass* k
if (actual_receiver_is_exact) { if (actual_receiver_is_exact) {
// In case of evolution, there is a dependence on every inlined method, since each // In case of evolution, there is a dependence on every inlined method, since each
// such method can be changed when its class is redefined. // such method can be changed when its class is redefined.
ciMethod* exact_method = dest_method->resolve_invoke(calling_klass, actual_receiver); ciMethod* exact_method = callee->resolve_invoke(calling_klass, actual_receiver);
if (exact_method != NULL) { if (exact_method != NULL) {
#ifndef PRODUCT #ifndef PRODUCT
if (PrintOpto) { if (PrintOpto) {
......
...@@ -469,10 +469,6 @@ class Parse : public GraphKit { ...@@ -469,10 +469,6 @@ class Parse : public GraphKit {
// Helper function to uncommon-trap or bailout for non-compilable call-sites // Helper function to uncommon-trap or bailout for non-compilable call-sites
bool can_not_compile_call_site(ciMethod *dest_method, ciInstanceKlass *klass); bool can_not_compile_call_site(ciMethod *dest_method, ciInstanceKlass *klass);
// Helper function to identify inlining potential at call-site
ciMethod* optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass* klass,
ciMethod *dest_method, const TypeOopPtr* receiver_type);
// Helper function to setup for type-profile based inlining // Helper function to setup for type-profile based inlining
bool prepare_type_profile_inline(ciInstanceKlass* prof_klass, ciMethod* prof_method); bool prepare_type_profile_inline(ciInstanceKlass* prof_klass, ciMethod* prof_method);
......
...@@ -1404,7 +1404,8 @@ void Parse::do_one_block() { ...@@ -1404,7 +1404,8 @@ void Parse::do_one_block() {
do_one_bytecode(); do_one_bytecode();
assert(!have_se || stopped() || failing() || (sp() - pre_bc_sp) == depth, "correct depth prediction"); assert(!have_se || stopped() || failing() || (sp() - pre_bc_sp) == depth,
err_msg_res("incorrect depth prediction: sp=%d, pre_bc_sp=%d, depth=%d", sp(), pre_bc_sp, depth));
do_exceptions(); do_exceptions();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册