8264079: Improve abstractions
Reviewed-by: vlivanov, ahgross, thartmann, rhalade
This commit is contained in:
parent
138f59806f
commit
a3acce5210
@ -1237,9 +1237,9 @@ class ConcreteMethodFinder : public AbstractClassHierarchyWalker {
|
|||||||
virtual Klass* find_witness_in(KlassDepChange& changes);
|
virtual Klass* find_witness_in(KlassDepChange& changes);
|
||||||
virtual Klass* find_witness_anywhere(InstanceKlass* context_type);
|
virtual Klass* find_witness_anywhere(InstanceKlass* context_type);
|
||||||
|
|
||||||
|
public:
|
||||||
bool witnessed_reabstraction_in_supers(Klass* k);
|
bool witnessed_reabstraction_in_supers(Klass* k);
|
||||||
|
|
||||||
public:
|
|
||||||
ConcreteMethodFinder(Method* m, Klass* participant = NULL) : AbstractClassHierarchyWalker(participant) {
|
ConcreteMethodFinder(Method* m, Klass* participant = NULL) : AbstractClassHierarchyWalker(participant) {
|
||||||
assert(m != NULL && m->is_method(), "sanity");
|
assert(m != NULL && m->is_method(), "sanity");
|
||||||
_name = m->name();
|
_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.
|
// If a class (or interface) has a unique concrete method uniqm, return NULL.
|
||||||
// Otherwise, return a class that contains an interfering method.
|
// Otherwise, return a class that contains an interfering method.
|
||||||
Klass* Dependencies::check_unique_concrete_method(InstanceKlass* ctxk,
|
Klass* Dependencies::check_unique_concrete_method(InstanceKlass* ctxk,
|
||||||
Method* uniqm,
|
Method* uniqm,
|
||||||
NewKlassDepChange* changes) {
|
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());
|
ConcreteMethodFinder wf(uniqm, uniqm->method_holder());
|
||||||
Klass* k = wf.find_witness(ctxk, changes);
|
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.
|
// Find the set of all non-abstract methods under ctxk that match m.
|
||||||
// (The method m must be defined or inherited in ctxk.)
|
// (The method m must be defined or inherited in ctxk.)
|
||||||
// Include m itself in the set, unless it is abstract.
|
// 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.)
|
// (This can happen if m is inherited into ctxk and fm overrides it.)
|
||||||
return NULL;
|
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
|
#ifndef PRODUCT
|
||||||
// Make sure the dependency mechanism will pass this discovery:
|
// Make sure the dependency mechanism will pass this discovery:
|
||||||
if (VerifyDependencies && fm != NULL) {
|
if (VerifyDependencies && fm != NULL) {
|
||||||
|
@ -384,6 +384,9 @@ class Dependencies: public ResourceObj {
|
|||||||
static bool is_concrete_method(Method* m, Klass* k); // m is invocable
|
static bool is_concrete_method(Method* m, Klass* k); // m is invocable
|
||||||
static Klass* find_finalizable_subclass(InstanceKlass* ik);
|
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.
|
// These versions of the concreteness queries work through the CI.
|
||||||
// The CI versions are allowed to skew sometimes from the VM
|
// The CI versions are allowed to skew sometimes from the VM
|
||||||
// (oop-based) versions. The cost of such a difference is a
|
// (oop-based) versions. The cost of such a difference is a
|
||||||
|
@ -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()));
|
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;
|
methodHandle ucm;
|
||||||
{
|
{
|
||||||
MutexLocker locker(Compile_lock);
|
MutexLocker locker(Compile_lock);
|
||||||
|
Loading…
Reference in New Issue
Block a user