8223171: Redundant nmethod dependencies for effectively final methods

Reviewed-by: dlong
This commit is contained in:
Vladimir Ivanov 2019-05-06 12:15:49 -07:00
parent c7faef0785
commit 75d4f24c97
8 changed files with 38 additions and 7 deletions

@ -1988,8 +1988,9 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
}
if (cha_monomorphic_target != NULL) {
assert(!target->can_be_statically_bound() || target == cha_monomorphic_target, "");
assert(!cha_monomorphic_target->is_abstract(), "");
if (!target->is_final_method() && !target->is_private()) {
if (!cha_monomorphic_target->can_be_statically_bound(actual_recv)) {
// If we inlined because CHA revealed only a single target method,
// then we are dependent on that target method not getting overridden
// by dynamic class loading. Be sure to test the "static" receiver

@ -764,6 +764,14 @@ ciMethod* ciMethod::find_monomorphic_target(ciInstanceKlass* caller,
return CURRENT_THREAD_ENV->get_method(target());
}
// ------------------------------------------------------------------
// ciMethod::can_be_statically_bound
//
// Tries to determine whether a method can be statically bound in some context.
bool ciMethod::can_be_statically_bound(ciInstanceKlass* context) const {
return (holder() == context) && can_be_statically_bound();
}
// ------------------------------------------------------------------
// ciMethod::resolve_invoke
//

@ -352,6 +352,8 @@ class ciMethod : public ciMetadata {
bool is_unboxing_method() const;
bool is_object_initializer() const;
bool can_be_statically_bound(ciInstanceKlass* context) const;
// Replay data methods
void dump_name_as_ascii(outputStream* st);
void dump_replay_data(outputStream* st);

@ -108,6 +108,7 @@ void Dependencies::assert_concrete_with_no_concrete_subtype(ciKlass* ctxk) {
void Dependencies::assert_unique_concrete_method(ciKlass* ctxk, ciMethod* uniqm) {
check_ctxk(ctxk);
check_unique_method(ctxk, uniqm);
assert_common_2(unique_concrete_method, ctxk, uniqm);
}
@ -180,6 +181,7 @@ void Dependencies::assert_abstract_with_unique_concrete_subtype(Klass* ctxk, Kla
void Dependencies::assert_unique_concrete_method(Klass* ctxk, Method* uniqm) {
check_ctxk(ctxk);
check_unique_method(ctxk, uniqm);
assert_common_2(unique_concrete_method, DepValue(_oop_recorder, ctxk), DepValue(_oop_recorder, uniqm));
}

@ -27,6 +27,7 @@
#include "ci/ciCallSite.hpp"
#include "ci/ciKlass.hpp"
#include "ci/ciMethod.hpp"
#include "ci/ciMethodHandle.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/compressedStream.hpp"
@ -341,6 +342,9 @@ class Dependencies: public ResourceObj {
check_ctxk(ctxk);
assert(!is_concrete_klass(ctxk->as_instance_klass()), "must be abstract");
}
static void check_unique_method(ciKlass* ctxk, ciMethod* m) {
assert(!m->can_be_statically_bound(ctxk->as_instance_klass()), "redundant");
}
void assert_common_1(DepType dept, ciBaseObject* x);
void assert_common_2(DepType dept, ciBaseObject* x0, ciBaseObject* x1);
@ -368,6 +372,10 @@ class Dependencies: public ResourceObj {
check_ctxk(ctxk);
assert(ctxk->is_abstract(), "must be abstract");
}
static void check_unique_method(Klass* ctxk, Method* m) {
assert(!m->can_be_statically_bound(InstanceKlass::cast(ctxk)), "redundant");
}
void assert_common_1(DepType dept, DepValue x);
void assert_common_2(DepType dept, DepValue x0, DepValue x1);

@ -624,6 +624,10 @@ bool Method::can_be_statically_bound() const {
return can_be_statically_bound(method_holder()->access_flags());
}
bool Method::can_be_statically_bound(InstanceKlass* context) const {
return (method_holder() == context) && can_be_statically_bound();
}
bool Method::is_accessor() const {
return is_getter() || is_setter();
}

@ -619,6 +619,7 @@ class Method : public Metadata {
// true if method needs no dynamic dispatch (final and/or no vtable entry)
bool can_be_statically_bound() const;
bool can_be_statically_bound(InstanceKlass* context) const;
bool can_be_statically_bound(AccessFlags class_access_flags) const;
// returns true if the method has any backward branches.

@ -1152,14 +1152,19 @@ ciMethod* Compile::optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass*
cha_monomorphic_target = NULL;
}
}
if (cha_monomorphic_target != NULL) {
// Hardwiring a virtual.
// If we inlined because CHA revealed only a single target method,
// then we are dependent on that target method not getting overridden
// by dynamic class loading. Be sure to test the "static" receiver
// dest_method here, as opposed to the actual receiver, which may
// falsely lead us to believe that the receiver is final or private.
dependencies()->assert_unique_concrete_method(actual_receiver, cha_monomorphic_target);
assert(!callee->can_be_statically_bound(), "should have been handled earlier");
assert(!cha_monomorphic_target->is_abstract(), "");
if (!cha_monomorphic_target->can_be_statically_bound(actual_receiver)) {
// If we inlined because CHA revealed only a single target method,
// then we are dependent on that target method not getting overridden
// by dynamic class loading. Be sure to test the "static" receiver
// dest_method here, as opposed to the actual receiver, which may
// falsely lead us to believe that the receiver is final or private.
dependencies()->assert_unique_concrete_method(actual_receiver, cha_monomorphic_target);
}
return cha_monomorphic_target;
}