mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 23:34:52 +02:00
6986483: CHA: optimize calls through interfaces
Reviewed-by: neliasso, thartmann
This commit is contained in:
parent
46a57587dc
commit
ac3711e9cd
11 changed files with 1113 additions and 62 deletions
|
@ -1942,7 +1942,8 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
|
|||
// Use CHA on the receiver to select a more precise method.
|
||||
cha_monomorphic_target = target->find_monomorphic_target(calling_klass, callee_holder, actual_recv);
|
||||
} else if (code == Bytecodes::_invokeinterface && callee_holder->is_loaded() && receiver != NULL) {
|
||||
// if there is only one implementor of this interface then we
|
||||
assert(callee_holder->is_interface(), "invokeinterface to non interface?");
|
||||
// If there is only one implementor of this interface then we
|
||||
// may be able bind this invoke directly to the implementing
|
||||
// klass but we need both a dependence on the single interface
|
||||
// and on the method we bind to. Additionally since all we know
|
||||
|
@ -1950,53 +1951,44 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
|
|||
// interface we have to insert a check that it's the class we
|
||||
// expect. Interface types are not checked by the verifier so
|
||||
// they are roughly equivalent to Object.
|
||||
// The number of implementors for declared_interface is less or
|
||||
// equal to the number of implementors for target->holder() so
|
||||
// if number of implementors of target->holder() == 1 then
|
||||
// number of implementors for decl_interface is 0 or 1. If
|
||||
// it's 0 then no class implements decl_interface and there's
|
||||
// no point in inlining.
|
||||
ciInstanceKlass* singleton = NULL;
|
||||
if (target->holder()->nof_implementors() == 1) {
|
||||
singleton = target->holder()->implementor();
|
||||
assert(singleton != NULL && singleton != target->holder(),
|
||||
"just checking");
|
||||
|
||||
assert(holder->is_interface(), "invokeinterface to non interface?");
|
||||
ciInstanceKlass* decl_interface = (ciInstanceKlass*)holder;
|
||||
// the number of implementors for decl_interface is less or
|
||||
// equal to the number of implementors for target->holder() so
|
||||
// if number of implementors of target->holder() == 1 then
|
||||
// number of implementors for decl_interface is 0 or 1. If
|
||||
// it's 0 then no class implements decl_interface and there's
|
||||
// no point in inlining.
|
||||
if (!holder->is_loaded() || decl_interface->nof_implementors() != 1 || decl_interface->has_nonstatic_concrete_methods()) {
|
||||
singleton = NULL;
|
||||
}
|
||||
}
|
||||
if (singleton) {
|
||||
cha_monomorphic_target = target->find_monomorphic_target(calling_klass, target->holder(), singleton);
|
||||
ciInstanceKlass* declared_interface = callee_holder;
|
||||
if (declared_interface->nof_implementors() == 1 &&
|
||||
(!target->is_default_method() || target->is_overpass()) /* CHA doesn't support default methods yet. */) {
|
||||
singleton = declared_interface->implementor();
|
||||
assert(singleton != NULL && singleton != declared_interface, "");
|
||||
cha_monomorphic_target = target->find_monomorphic_target(calling_klass, declared_interface, singleton);
|
||||
if (cha_monomorphic_target != NULL) {
|
||||
// If CHA is able to bind this invoke then update the class
|
||||
// to match that class, otherwise klass will refer to the
|
||||
// interface.
|
||||
klass = cha_monomorphic_target->holder();
|
||||
actual_recv = target->holder();
|
||||
if (cha_monomorphic_target->holder() != compilation()->env()->Object_klass()) {
|
||||
// If CHA is able to bind this invoke then update the class
|
||||
// to match that class, otherwise klass will refer to the
|
||||
// interface.
|
||||
klass = cha_monomorphic_target->holder();
|
||||
actual_recv = declared_interface;
|
||||
|
||||
// insert a check it's really the expected class.
|
||||
CheckCast* c = new CheckCast(klass, receiver, copy_state_for_exception());
|
||||
c->set_incompatible_class_change_check();
|
||||
c->set_direct_compare(klass->is_final());
|
||||
// pass the result of the checkcast so that the compiler has
|
||||
// more accurate type info in the inlinee
|
||||
better_receiver = append_split(c);
|
||||
// insert a check it's really the expected class.
|
||||
CheckCast* c = new CheckCast(klass, receiver, copy_state_for_exception());
|
||||
c->set_incompatible_class_change_check();
|
||||
c->set_direct_compare(klass->is_final());
|
||||
// pass the result of the checkcast so that the compiler has
|
||||
// more accurate type info in the inlinee
|
||||
better_receiver = append_split(c);
|
||||
} else {
|
||||
cha_monomorphic_target = NULL; // subtype check against Object is useless
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cha_monomorphic_target != NULL) {
|
||||
if (cha_monomorphic_target->is_abstract()) {
|
||||
// Do not optimize for abstract methods
|
||||
cha_monomorphic_target = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (cha_monomorphic_target != NULL) {
|
||||
assert(!cha_monomorphic_target->is_abstract(), "");
|
||||
if (!(target->is_final_method())) {
|
||||
// If we inlined because CHA revealed only a single target method,
|
||||
// then we are dependent on that target method not getting overridden
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue