8264079: Improve abstractions

Reviewed-by: vlivanov, ahgross, thartmann, rhalade
This commit is contained in:
Jamsheed Mohammed C M 2021-04-08 03:30:31 +00:00 committed by Henry Jen
parent 138f59806f
commit a3acce5210
3 changed files with 83 additions and 10 deletions

View File

@ -1237,9 +1237,9 @@ class ConcreteMethodFinder : public AbstractClassHierarchyWalker {
virtual Klass* find_witness_in(KlassDepChange& changes);
virtual Klass* find_witness_anywhere(InstanceKlass* context_type);
public:
bool witnessed_reabstraction_in_supers(Klass* k);
public:
ConcreteMethodFinder(Method* m, Klass* participant = NULL) : AbstractClassHierarchyWalker(participant) {
assert(m != NULL && m->is_method(), "sanity");
_name = m->name();
@ -1752,20 +1752,90 @@ Klass* Dependencies::find_unique_concrete_subtype(InstanceKlass* ctxk) {
}
}
// Try to determine whether root method in some context is concrete or not based on the information about the unique method
// in that context. It exploits the fact that concrete root method is always inherited into the context when there's a unique method.
// Hence, unique method holder is always a supertype of the context class when root method is concrete.
// Examples for concrete_root_method
// C (C.m uniqm)
// |
// CX (ctxk) uniqm is inherited into context.
//
// CX (ctxk) (CX.m uniqm) here uniqm is defined in ctxk.
// Examples for !concrete_root_method
// CX (ctxk)
// |
// C (C.m uniqm) uniqm is in subtype of ctxk.
bool Dependencies::is_concrete_root_method(Method* uniqm, InstanceKlass* ctxk) {
if (uniqm == NULL) {
return false; // match Dependencies::is_concrete_method() behavior
}
// Theoretically, the "direction" of subtype check matters here.
// On one hand, in case of interface context with a single implementor, uniqm can be in a superclass of the implementor which
// is not related to context class.
// On another hand, uniqm could come from an interface unrelated to the context class, but right now it is not possible:
// it is required that uniqm->method_holder() is the participant (uniqm->method_holder() <: ctxk), hence a default method
// can't be used as unique.
if (ctxk->is_interface()) {
InstanceKlass* implementor = ctxk->implementor();
assert(implementor != ctxk, "single implementor only"); // should have been invalidated earlier
ctxk = implementor;
}
InstanceKlass* holder = uniqm->method_holder();
assert(!holder->is_interface(), "no default methods allowed");
assert(ctxk->is_subclass_of(holder) || holder->is_subclass_of(ctxk), "not related");
return ctxk->is_subclass_of(holder);
}
// If a class (or interface) has a unique concrete method uniqm, return NULL.
// Otherwise, return a class that contains an interfering method.
Klass* Dependencies::check_unique_concrete_method(InstanceKlass* ctxk,
Method* uniqm,
NewKlassDepChange* changes) {
// Here is a missing optimization: If uniqm->is_final(),
// we don't really need to search beneath it for overrides.
// This is probably not important, since we don't use dependencies
// to track final methods. (They can't be "definalized".)
ConcreteMethodFinder wf(uniqm, uniqm->method_holder());
Klass* k = wf.find_witness(ctxk, changes);
return k;
if (k != NULL) {
return k;
}
if (!Dependencies::is_concrete_root_method(uniqm, ctxk) || changes != NULL) {
Klass* conck = find_witness_AME(ctxk, uniqm, changes);
if (conck != NULL) {
// Found a concrete subtype 'conck' which does not override abstract root method.
return conck;
}
}
return NULL;
}
// Search for AME.
// There are two version of checks.
// 1) Spot checking version(Classload time). Newly added class is checked for AME.
// Checks whether abstract/overpass method is inherited into/declared in newly added concrete class.
// 2) Compile time analysis for abstract/overpass(abstract klass) root_m. The non uniqm subtrees are checked for concrete classes.
Klass* Dependencies::find_witness_AME(InstanceKlass* ctxk, Method* m, KlassDepChange* changes) {
if (m != NULL) {
if (changes != NULL) {
// Spot checking version.
ConcreteMethodFinder wf(m);
Klass* new_type = changes->as_new_klass_change()->new_type();
if (wf.witnessed_reabstraction_in_supers(new_type)) {
return new_type;
}
} else {
// Note: It is required that uniqm->method_holder() is the participant (see ClassHierarchyWalker::found_method()).
ConcreteSubtypeFinder wf(m->method_holder());
Klass* conck = wf.find_witness(ctxk);
if (conck != NULL) {
Method* cm = InstanceKlass::cast(conck)->find_instance_method(m->name(), m->signature(), Klass::PrivateLookupMode::skip);
if (!Dependencies::is_concrete_method(cm, conck)) {
return conck;
}
}
}
}
return NULL;
}
// Find the set of all non-abstract methods under ctxk that match m.
// (The method m must be defined or inherited in ctxk.)
// Include m itself in the set, unless it is abstract.
@ -1796,7 +1866,11 @@ Method* Dependencies::find_unique_concrete_method(InstanceKlass* ctxk, Method* m
// (This can happen if m is inherited into ctxk and fm overrides it.)
return NULL;
}
} else if (Dependencies::find_witness_AME(ctxk, fm) != NULL) {
// Found a concrete subtype which does not override abstract root method.
return NULL;
}
assert(Dependencies::is_concrete_root_method(fm, ctxk) == Dependencies::is_concrete_method(m, ctxk), "mismatch");
#ifndef PRODUCT
// Make sure the dependency mechanism will pass this discovery:
if (VerifyDependencies && fm != NULL) {

View File

@ -384,6 +384,9 @@ class Dependencies: public ResourceObj {
static bool is_concrete_method(Method* m, Klass* k); // m is invocable
static Klass* find_finalizable_subclass(InstanceKlass* ik);
static bool is_concrete_root_method(Method* uniqm, InstanceKlass* ctxk);
static Klass* find_witness_AME(InstanceKlass* ctxk, Method* m, KlassDepChange* changes = NULL);
// These versions of the concreteness queries work through the CI.
// The CI versions are allowed to skew sometimes from the VM
// (oop-based) versions. The cost of such a difference is a

View File

@ -457,10 +457,6 @@ C2V_VMENTRY_NULL(jobject, findUniqueConcreteMethod, (JNIEnv* env, jobject, jobje
JVMCI_THROW_MSG_NULL(InternalError, err_msg("Effectively static method %s.%s should be handled in Java code", method->method_holder()->external_name(), method->external_name()));
}
if (method->is_abstract()) {
return NULL;
}
methodHandle ucm;
{
MutexLocker locker(Compile_lock);