mirror of
https://github.com/openjdk/jdk.git
synced 2026-07-30 04:43:27 +00:00
8064524: Compiler code generation improvements
Reviewed-by: jrose, acorn, vlivanov
This commit is contained in:
parent
3f915eeafd
commit
2080004ef0
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -560,7 +560,7 @@ void Dependencies::print_dependency(DepType dept, GrowableArray<DepArgument>* ar
|
||||
put_star = !Dependencies::is_concrete_klass((Klass*)arg.metadata_value());
|
||||
} else if (arg.is_method()) {
|
||||
what = "method ";
|
||||
put_star = !Dependencies::is_concrete_method((Method*)arg.metadata_value());
|
||||
put_star = !Dependencies::is_concrete_method((Method*)arg.metadata_value(), NULL);
|
||||
} else if (arg.is_klass()) {
|
||||
what = "class ";
|
||||
} else {
|
||||
@ -878,8 +878,8 @@ class ClassHierarchyWalker {
|
||||
// Static methods don't override non-static so punt
|
||||
return true;
|
||||
}
|
||||
if ( !Dependencies::is_concrete_method(lm)
|
||||
&& !Dependencies::is_concrete_method(m)
|
||||
if ( !Dependencies::is_concrete_method(lm, k)
|
||||
&& !Dependencies::is_concrete_method(m, ctxk)
|
||||
&& lm->method_holder()->is_subtype_of(m->method_holder()))
|
||||
// Method m is overridden by lm, but both are non-concrete.
|
||||
return true;
|
||||
@ -915,8 +915,17 @@ class ClassHierarchyWalker {
|
||||
} else if (!k->oop_is_instance()) {
|
||||
return false; // no methods to find in an array type
|
||||
} else {
|
||||
Method* m = InstanceKlass::cast(k)->find_method(_name, _signature);
|
||||
if (m == NULL || !Dependencies::is_concrete_method(m)) return false;
|
||||
// Search class hierarchy first.
|
||||
Method* m = InstanceKlass::cast(k)->find_instance_method(_name, _signature);
|
||||
if (!Dependencies::is_concrete_method(m, k)) {
|
||||
// Check interface defaults also, if any exist.
|
||||
Array<Method*>* default_methods = InstanceKlass::cast(k)->default_methods();
|
||||
if (default_methods == NULL)
|
||||
return false;
|
||||
m = InstanceKlass::cast(k)->find_method(default_methods, _name, _signature);
|
||||
if (!Dependencies::is_concrete_method(m, NULL))
|
||||
return false;
|
||||
}
|
||||
_found_methods[_num_participants] = m;
|
||||
// Note: If add_participant(k) is called,
|
||||
// the method m will already be memoized for it.
|
||||
@ -1209,15 +1218,17 @@ bool Dependencies::is_concrete_klass(Klass* k) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Dependencies::is_concrete_method(Method* m) {
|
||||
// Statics are irrelevant to virtual call sites.
|
||||
if (m->is_static()) return false;
|
||||
|
||||
// We could also return false if m does not yet appear to be
|
||||
// executed, if the VM version supports this distinction also.
|
||||
// Default methods are considered "concrete" as well.
|
||||
return !m->is_abstract() &&
|
||||
!m->is_overpass(); // error functions aren't concrete
|
||||
bool Dependencies::is_concrete_method(Method* m, Klass * k) {
|
||||
// NULL is not a concrete method,
|
||||
// statics are irrelevant to virtual call sites,
|
||||
// abstract methods are not concrete,
|
||||
// overpass (error) methods are not concrete if k is abstract
|
||||
//
|
||||
// note "true" is conservative answer --
|
||||
// overpass clause is false if k == NULL, implies return true if
|
||||
// answer depends on overpass clause.
|
||||
return ! ( m == NULL || m -> is_static() || m -> is_abstract() ||
|
||||
m->is_overpass() && k != NULL && k -> is_abstract() );
|
||||
}
|
||||
|
||||
|
||||
@ -1242,16 +1253,6 @@ bool Dependencies::is_concrete_klass(ciInstanceKlass* k) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Dependencies::is_concrete_method(ciMethod* m) {
|
||||
// Statics are irrelevant to virtual call sites.
|
||||
if (m->is_static()) return false;
|
||||
|
||||
// We could also return false if m does not yet appear to be
|
||||
// executed, if the VM version supports this distinction also.
|
||||
return !m->is_abstract();
|
||||
}
|
||||
|
||||
|
||||
bool Dependencies::has_finalizable_subclass(ciInstanceKlass* k) {
|
||||
return k->has_finalizable_subclass();
|
||||
}
|
||||
@ -1469,7 +1470,7 @@ Method* Dependencies::find_unique_concrete_method(Klass* ctxk, Method* m) {
|
||||
Klass* wit = wf.find_witness_definer(ctxk);
|
||||
if (wit != NULL) return NULL; // Too many witnesses.
|
||||
Method* fm = wf.found_method(0); // Will be NULL if num_parts == 0.
|
||||
if (Dependencies::is_concrete_method(m)) {
|
||||
if (Dependencies::is_concrete_method(m, ctxk)) {
|
||||
if (fm == NULL) {
|
||||
// It turns out that m was always the only implementation.
|
||||
fm = m;
|
||||
@ -1499,61 +1500,6 @@ Klass* Dependencies::check_exclusive_concrete_methods(Klass* ctxk,
|
||||
return wf.find_witness_definer(ctxk, changes);
|
||||
}
|
||||
|
||||
// Find the set of all non-abstract methods under ctxk that match m[0].
|
||||
// (The method m[0] must be defined or inherited in ctxk.)
|
||||
// Include m itself in the set, unless it is abstract.
|
||||
// Fill the given array m[0..(mlen-1)] with this set, and return the length.
|
||||
// (The length may be zero if no concrete methods are found anywhere.)
|
||||
// If there are too many concrete methods to fit in marray, return -1.
|
||||
int Dependencies::find_exclusive_concrete_methods(Klass* ctxk,
|
||||
int mlen,
|
||||
Method* marray[]) {
|
||||
Method* m0 = marray[0];
|
||||
ClassHierarchyWalker wf(m0);
|
||||
assert(wf.check_method_context(ctxk, m0), "proper context");
|
||||
wf.record_witnesses(mlen);
|
||||
bool participants_hide_witnesses = true;
|
||||
Klass* wit = wf.find_witness_definer(ctxk);
|
||||
if (wit != NULL) return -1; // Too many witnesses.
|
||||
int num = wf.num_participants();
|
||||
assert(num <= mlen, "oob");
|
||||
// Keep track of whether m is also part of the result set.
|
||||
int mfill = 0;
|
||||
assert(marray[mfill] == m0, "sanity");
|
||||
if (Dependencies::is_concrete_method(m0))
|
||||
mfill++; // keep m0 as marray[0], the first result
|
||||
for (int i = 0; i < num; i++) {
|
||||
Method* fm = wf.found_method(i);
|
||||
if (fm == m0) continue; // Already put this guy in the list.
|
||||
if (mfill == mlen) {
|
||||
return -1; // Oops. Too many methods after all!
|
||||
}
|
||||
marray[mfill++] = fm;
|
||||
}
|
||||
#ifndef PRODUCT
|
||||
// Make sure the dependency mechanism will pass this discovery:
|
||||
if (VerifyDependencies) {
|
||||
// Turn off dependency tracing while actually testing deps.
|
||||
FlagSetting fs(TraceDependencies, false);
|
||||
switch (mfill) {
|
||||
case 1:
|
||||
guarantee(NULL == (void *)check_unique_concrete_method(ctxk, marray[0]),
|
||||
"verify dep.");
|
||||
break;
|
||||
case 2:
|
||||
guarantee(NULL == (void *)
|
||||
check_exclusive_concrete_methods(ctxk, marray[0], marray[1]),
|
||||
"verify dep.");
|
||||
break;
|
||||
default:
|
||||
ShouldNotReachHere(); // mlen > 2 yet supported
|
||||
}
|
||||
}
|
||||
#endif //PRODUCT
|
||||
return mfill;
|
||||
}
|
||||
|
||||
|
||||
Klass* Dependencies::check_has_no_finalizable_subclasses(Klass* ctxk, KlassDepChange* changes) {
|
||||
Klass* search_at = ctxk;
|
||||
if (changes != NULL)
|
||||
@ -1561,7 +1507,6 @@ Klass* Dependencies::check_has_no_finalizable_subclasses(Klass* ctxk, KlassDepCh
|
||||
return find_finalizable_subclass(search_at);
|
||||
}
|
||||
|
||||
|
||||
Klass* Dependencies::check_call_site_target_value(oop call_site, oop method_handle, CallSiteDepChange* changes) {
|
||||
assert(call_site ->is_a(SystemDictionary::CallSite_klass()), "sanity");
|
||||
assert(method_handle->is_a(SystemDictionary::MethodHandle_klass()), "sanity");
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -288,7 +288,7 @@ class Dependencies: public ResourceObj {
|
||||
// In that case, there would be a middle ground between concrete
|
||||
// and abstract (as defined by the Java language and VM).
|
||||
static bool is_concrete_klass(Klass* k); // k is instantiable
|
||||
static bool is_concrete_method(Method* m); // m is invocable
|
||||
static bool is_concrete_method(Method* m, Klass* k); // m is invocable
|
||||
static Klass* find_finalizable_subclass(Klass* k);
|
||||
|
||||
// These versions of the concreteness queries work through the CI.
|
||||
@ -302,7 +302,6 @@ class Dependencies: public ResourceObj {
|
||||
// not go back into the VM to get their value; they must cache the
|
||||
// bit in the CI, either eagerly or lazily.)
|
||||
static bool is_concrete_klass(ciInstanceKlass* k); // k appears instantiable
|
||||
static bool is_concrete_method(ciMethod* m); // m appears invocable
|
||||
static bool has_finalizable_subclass(ciInstanceKlass* k);
|
||||
|
||||
// As a general rule, it is OK to compile under the assumption that
|
||||
@ -349,7 +348,6 @@ class Dependencies: public ResourceObj {
|
||||
static Klass* find_unique_concrete_subtype(Klass* ctxk);
|
||||
static Method* find_unique_concrete_method(Klass* ctxk, Method* m);
|
||||
static int find_exclusive_concrete_subtypes(Klass* ctxk, int klen, Klass* k[]);
|
||||
static int find_exclusive_concrete_methods(Klass* ctxk, int mlen, Method* m[]);
|
||||
|
||||
// Create the encoding which will be stored in an nmethod.
|
||||
void encode_content_bytes();
|
||||
|
||||
@ -320,7 +320,7 @@ int LinkResolver::vtable_index_of_interface_method(KlassHandle klass,
|
||||
// First check in default method array
|
||||
if (!resolved_method->is_abstract() &&
|
||||
(InstanceKlass::cast(klass())->default_methods() != NULL)) {
|
||||
int index = InstanceKlass::find_method_index(InstanceKlass::cast(klass())->default_methods(), name, signature, false);
|
||||
int index = InstanceKlass::find_method_index(InstanceKlass::cast(klass())->default_methods(), name, signature, false, false);
|
||||
if (index >= 0 ) {
|
||||
vtable_index = InstanceKlass::cast(klass())->default_vtable_indices()->at(index);
|
||||
}
|
||||
|
||||
@ -1420,32 +1420,41 @@ Method* InstanceKlass::find_method(Symbol* name, Symbol* signature) const {
|
||||
}
|
||||
|
||||
Method* InstanceKlass::find_method_impl(Symbol* name, Symbol* signature, bool skipping_overpass) const {
|
||||
return InstanceKlass::find_method_impl(methods(), name, signature, skipping_overpass);
|
||||
return InstanceKlass::find_method_impl(methods(), name, signature, skipping_overpass, false);
|
||||
}
|
||||
|
||||
// find_instance_method looks up the name/signature in the local methods array
|
||||
// and skips over static methods
|
||||
Method* InstanceKlass::find_instance_method(
|
||||
Array<Method*>* methods, Symbol* name, Symbol* signature) {
|
||||
Method* meth = InstanceKlass::find_method(methods, name, signature);
|
||||
if (meth != NULL && meth->is_static()) {
|
||||
meth = NULL;
|
||||
}
|
||||
Method* meth = InstanceKlass::find_method_impl(methods, name, signature, false, true);
|
||||
return meth;
|
||||
}
|
||||
|
||||
// find_instance_method looks up the name/signature in the local methods array
|
||||
// and skips over static methods
|
||||
Method* InstanceKlass::find_instance_method(Symbol* name, Symbol* signature) {
|
||||
return InstanceKlass::find_instance_method(methods(), name, signature);
|
||||
}
|
||||
|
||||
// find_method looks up the name/signature in the local methods array
|
||||
Method* InstanceKlass::find_method(
|
||||
Array<Method*>* methods, Symbol* name, Symbol* signature) {
|
||||
return InstanceKlass::find_method_impl(methods, name, signature, false);
|
||||
return InstanceKlass::find_method_impl(methods, name, signature, false, false);
|
||||
}
|
||||
|
||||
Method* InstanceKlass::find_method_impl(
|
||||
Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass) {
|
||||
int hit = find_method_index(methods, name, signature, skipping_overpass);
|
||||
Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass, bool skipping_static) {
|
||||
int hit = find_method_index(methods, name, signature, skipping_overpass, skipping_static);
|
||||
return hit >= 0 ? methods->at(hit): NULL;
|
||||
}
|
||||
|
||||
bool InstanceKlass::method_matches(Method* m, Symbol* signature, bool skipping_overpass, bool skipping_static) {
|
||||
return (m->signature() == signature) &&
|
||||
(!skipping_overpass || !m->is_overpass()) &&
|
||||
(!skipping_static || !m->is_static());
|
||||
}
|
||||
|
||||
// Used directly for default_methods to find the index into the
|
||||
// default_vtable_indices, and indirectly by find_method
|
||||
// find_method_index looks in the local methods array to return the index
|
||||
@ -1454,13 +1463,14 @@ Method* InstanceKlass::find_method_impl(
|
||||
// is important during method resolution to prefer a static method, for example,
|
||||
// over an overpass method.
|
||||
int InstanceKlass::find_method_index(
|
||||
Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass) {
|
||||
Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass, bool skipping_static) {
|
||||
int hit = binary_search(methods, name);
|
||||
if (hit != -1) {
|
||||
Method* m = methods->at(hit);
|
||||
|
||||
// Do linear search to find matching signature. First, quick check
|
||||
// for common case, ignoring overpasses if requested.
|
||||
if ((m->signature() == signature) && (!skipping_overpass || !m->is_overpass())) return hit;
|
||||
if (method_matches(m, signature, skipping_overpass, skipping_static)) return hit;
|
||||
|
||||
// search downwards through overloaded methods
|
||||
int i;
|
||||
@ -1468,18 +1478,18 @@ int InstanceKlass::find_method_index(
|
||||
Method* m = methods->at(i);
|
||||
assert(m->is_method(), "must be method");
|
||||
if (m->name() != name) break;
|
||||
if ((m->signature() == signature) && (!skipping_overpass || !m->is_overpass())) return i;
|
||||
if (method_matches(m, signature, skipping_overpass, skipping_static)) return i;
|
||||
}
|
||||
// search upwards
|
||||
for (i = hit + 1; i < methods->length(); ++i) {
|
||||
Method* m = methods->at(i);
|
||||
assert(m->is_method(), "must be method");
|
||||
if (m->name() != name) break;
|
||||
if ((m->signature() == signature) && (!skipping_overpass || !m->is_overpass())) return i;
|
||||
if (method_matches(m, signature, skipping_overpass, skipping_static)) return i;
|
||||
}
|
||||
// not found
|
||||
#ifdef ASSERT
|
||||
int index = skipping_overpass ? -1 : linear_search(methods, name, signature);
|
||||
int index = skipping_overpass || skipping_static ? -1 : linear_search(methods, name, signature);
|
||||
assert(index == -1, err_msg("binary search should have found entry %d", index));
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -490,10 +490,16 @@ class InstanceKlass: public Klass {
|
||||
// find a local method (returns NULL if not found)
|
||||
Method* find_method(Symbol* name, Symbol* signature) const;
|
||||
static Method* find_method(Array<Method*>* methods, Symbol* name, Symbol* signature);
|
||||
|
||||
// find a local method, but skip static methods
|
||||
Method* find_instance_method(Symbol* name, Symbol* signature);
|
||||
static Method* find_instance_method(Array<Method*>* methods, Symbol* name, Symbol* signature);
|
||||
|
||||
// true if method matches signature and conforms to skipping_X conditions.
|
||||
static bool method_matches(Method* m, Symbol* signature, bool skipping_overpass, bool skipping_static);
|
||||
|
||||
// find a local method index in default_methods (returns -1 if not found)
|
||||
static int find_method_index(Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass);
|
||||
static int find_method_index(Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass, bool skipping_static);
|
||||
|
||||
// lookup operation (returns NULL if not found)
|
||||
Method* uncached_lookup_method(Symbol* name, Symbol* signature, MethodLookupMode mode) const;
|
||||
@ -1053,7 +1059,7 @@ private:
|
||||
|
||||
// find a local method (returns NULL if not found)
|
||||
Method* find_method_impl(Symbol* name, Symbol* signature, bool skipping_overpass) const;
|
||||
static Method* find_method_impl(Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass);
|
||||
static Method* find_method_impl(Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass, bool skipping_static);
|
||||
|
||||
// Free CHeap allocated fields.
|
||||
void release_C_heap_structures();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user