8256365: Clean up vtable initialization code

Reviewed-by: eosterlund, dholmes
This commit is contained in:
Coleen Phillimore 2020-11-18 14:12:48 +00:00
parent 4e5116c46e
commit fa8dce4f77
4 changed files with 93 additions and 100 deletions

View File

@ -2972,27 +2972,6 @@ bool InstanceKlass::is_same_class_package(oop other_class_loader,
}
}
// Returns true iff super_method can be overridden by a method in targetclassname
// See JLS 3rd edition 8.4.6.1
// Assumes name-signature match
// "this" is InstanceKlass of super_method which must exist
// note that the InstanceKlass of the method in the targetclassname has not always been created yet
bool InstanceKlass::is_override(const methodHandle& super_method, Handle targetclassloader, Symbol* targetclassname, TRAPS) {
// Private methods can not be overridden
if (super_method->is_private()) {
return false;
}
// If super method is accessible, then override
if ((super_method->is_protected()) ||
(super_method->is_public())) {
return true;
}
// Package-private methods are not inherited outside of package
assert(super_method->is_package_private(), "must be package private");
return(is_same_class_package(targetclassloader(), targetclassname));
}
static bool is_prohibited_package_slow(Symbol* class_name) {
// Caller has ResourceMark
int length;

View File

@ -512,9 +512,6 @@ public:
enclosing_method_attribute_size = 2
};
// method override check
bool is_override(const methodHandle& super_method, Handle targetclassloader, Symbol* targetclassname, TRAPS);
// package
PackageEntry* package() const { return _package_entry; }
ModuleEntry* module() const;

View File

@ -80,11 +80,10 @@ void klassVtable::compute_vtable_size_and_num_mirandas(
// go thru each method in the methods table to see if it needs a new entry
int len = methods->length();
for (int i = 0; i < len; i++) {
assert(methods->at(i)->is_method(), "must be a Method*");
methodHandle mh(THREAD, methods->at(i));
Method* method = methods->at(i);
if (needs_new_vtable_entry(mh, super, classloader, classname, class_flags, major_version, THREAD)) {
assert(!methods->at(i)->is_private(), "private methods should not need a vtable entry");
if (needs_new_vtable_entry(method, super, classloader, classname, class_flags, major_version)) {
assert(!method->is_private(), "private methods should not need a vtable entry");
vtable_length += vtableEntry::size(); // we need a new entry
}
}
@ -199,15 +198,13 @@ void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) {
// if override, replace in copy of super vtable, otherwise append to end
for (int i = 0; i < len; i++) {
// update_inherited_vtable can stop for gc - ensure using handles
HandleMark hm(THREAD);
assert(methods->at(i)->is_method(), "must be a Method*");
methodHandle mh(THREAD, methods->at(i));
bool needs_new_entry = update_inherited_vtable(ik(), mh, super_vtable_len, -1, checkconstraints, CHECK);
bool needs_new_entry = update_inherited_vtable(mh, super_vtable_len, -1, checkconstraints, CHECK);
if (needs_new_entry) {
put_method_at(mh(), initialized);
mh()->set_vtable_index(initialized); // set primary vtable index
mh->set_vtable_index(initialized); // set primary vtable index
initialized++;
}
}
@ -225,11 +222,9 @@ void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) {
assert(def_vtable_indices->length() == len, "reinit vtable len?");
}
for (int i = 0; i < len; i++) {
HandleMark hm(THREAD);
assert(default_methods->at(i)->is_method(), "must be a Method*");
methodHandle mh(THREAD, default_methods->at(i));
assert(!mh->is_private(), "private interface method in the default method list");
bool needs_new_entry = update_inherited_vtable(ik(), mh, super_vtable_len, i, checkconstraints, CHECK);
bool needs_new_entry = update_inherited_vtable(mh, super_vtable_len, i, checkconstraints, CHECK);
// needs new entry
if (needs_new_entry) {
@ -272,6 +267,25 @@ void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) {
}
}
// Returns true iff super_method can be overridden by a method in targetclassname
// See JLS 3rd edition 8.4.6.1
// Assumes name-signature match
// Note that the InstanceKlass of the method in the targetclassname has not always been created yet
static bool can_be_overridden(Method* super_method, Handle targetclassloader, Symbol* targetclassname) {
// Private methods can not be overridden
assert(!super_method->is_private(), "shouldn't call with a private method");
// If super method is accessible, then override
if ((super_method->is_protected()) ||
(super_method->is_public())) {
return true;
}
// Package-private methods are not inherited outside of package
assert(super_method->is_package_private(), "must be package private");
return(super_method->method_holder()->is_same_class_package(targetclassloader(), targetclassname));
}
// Called for cases where a method does not override its superclass' vtable entry
// For bytecodes not produced by javac together it is possible that a method does not override
// the superclass's method, but might indirectly override a super-super class's vtable entry
@ -287,30 +301,31 @@ void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) {
// Therefore: all package private methods need their own vtable entries for
// them to be the root of an inheritance overriding decision
// Package private methods may also override other vtable entries
InstanceKlass* klassVtable::find_transitive_override(InstanceKlass* initialsuper, const methodHandle& target_method,
int vtable_index, Handle target_loader, Symbol* target_classname, Thread * THREAD) {
InstanceKlass* klassVtable::find_transitive_override(InstanceKlass* initialsuper,
const methodHandle& target_method,
int vtable_index,
Handle target_loader,
Symbol* target_classname) {
InstanceKlass* superk = initialsuper;
while (superk != NULL && superk->super() != NULL) {
klassVtable ssVtable = (superk->super())->vtable();
if (vtable_index < ssVtable.length()) {
Method* super_method = ssVtable.method_at(vtable_index);
// get the class holding the matching method
// make sure you use that class for is_override
InstanceKlass* supermethodholder = super_method->method_holder();
#ifndef PRODUCT
Symbol* name= target_method()->name();
Symbol* signature = target_method()->signature();
assert(super_method->name() == name && super_method->signature() == signature, "vtable entry name/sig mismatch");
#endif
if (supermethodholder->is_override(methodHandle(THREAD, super_method), target_loader, target_classname, THREAD)) {
if (can_be_overridden(super_method, target_loader, target_classname)) {
if (log_develop_is_enabled(Trace, vtables)) {
ResourceMark rm(THREAD);
ResourceMark rm;
LogTarget(Trace, vtables) lt;
LogStream ls(lt);
char* sig = target_method()->name_and_sig_as_C_string();
ls.print("transitive overriding superclass %s with %s index %d, original flags: ",
supermethodholder->internal_name(),
super_method->method_holder()->internal_name(),
sig, vtable_index);
super_method->print_linkage_flags(&ls);
ls.print("overriders flags: ");
@ -360,12 +375,13 @@ static void log_vtables(int i, bool overrides, const methodHandle& target_method
// OR return true if a new vtable entry is required.
// Only called for InstanceKlass's, i.e. not for arrays
// If that changed, could not use _klass as handle for klass
bool klassVtable::update_inherited_vtable(InstanceKlass* klass, const methodHandle& target_method,
bool klassVtable::update_inherited_vtable(const methodHandle& target_method,
int super_vtable_len, int default_index,
bool checkconstraints, TRAPS) {
ResourceMark rm(THREAD);
bool allocate_new = true;
assert(klass->is_instance_klass(), "must be InstanceKlass");
InstanceKlass* klass = ik();
Array<int>* def_vtable_indices = NULL;
bool is_default = false;
@ -378,19 +394,19 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, const methodHand
if (default_index >= 0 ) {
is_default = true;
def_vtable_indices = klass->default_vtable_indices();
assert(!target_method()->is_private(), "private interface method flagged as default");
assert(!target_method->is_private(), "private interface method flagged as default");
assert(def_vtable_indices != NULL, "def vtable alloc?");
assert(default_index <= def_vtable_indices->length(), "def vtable len?");
} else {
assert(klass == target_method()->method_holder(), "caller resp.");
assert(klass == target_method->method_holder(), "caller resp.");
// Initialize the method's vtable index to "nonvirtual".
// If we allocate a vtable entry, we will update it to a non-negative number.
target_method()->set_vtable_index(Method::nonvirtual_vtable_index);
target_method->set_vtable_index(Method::nonvirtual_vtable_index);
}
// Private, static and <init> methods are never in
if (target_method()->is_private() || target_method()->is_static() ||
(target_method()->name()->fast_compare(vmSymbols::object_initializer_name()) == 0)) {
if (target_method->is_private() || target_method->is_static() ||
(target_method->name()->fast_compare(vmSymbols::object_initializer_name()) == 0)) {
return false;
}
@ -410,8 +426,8 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, const methodHand
// valid itable index, if so, don't change it.
// Overpass methods in an interface will be assigned an itable index later
// by an inheriting class.
if ((!is_default || !target_method()->has_itable_index())) {
target_method()->set_vtable_index(Method::pending_itable_index);
if ((!is_default || !target_method->has_itable_index())) {
target_method->set_vtable_index(Method::pending_itable_index);
}
}
@ -426,14 +442,16 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, const methodHand
// which can block for gc, once we are in this loop, use handles
// For classfiles built with >= jdk7, we now look for transitive overrides
Symbol* name = target_method()->name();
Symbol* signature = target_method()->signature();
Symbol* name = target_method->name();
Symbol* signature = target_method->signature();
Klass* target_klass = target_method()->method_holder();
Klass* target_klass = target_method->method_holder();
assert(target_klass != NULL, "impossible");
if (target_klass == NULL) {
target_klass = _klass;
}
HandleMark hm(THREAD);
Handle target_loader(THREAD, target_klass->class_loader());
Symbol* target_classname = target_klass->name();
@ -452,7 +470,7 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, const methodHand
// This is safe because the method at this slot should never get invoked.
// (TBD: put in a method to throw NoSuchMethodError if this slot is ever used.)
if (super_method->name() == name && super_method->signature() == signature &&
(!_klass->is_interface() ||
(!klass->is_interface() ||
!SystemDictionary::is_nonpublic_Object_method(super_method))) {
// get super_klass for method_holder for the found method
@ -463,23 +481,22 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, const methodHand
// private methods are also never overridden
if (!super_method->is_private() &&
(is_default
|| ((super_klass->is_override(methodHandle(THREAD, super_method), target_loader, target_classname, THREAD))
|| ((klass->major_version() >= VTABLE_TRANSITIVE_OVERRIDE_VERSION)
&& ((super_klass = find_transitive_override(super_klass,
target_method, i, target_loader,
target_classname, THREAD))
!= (InstanceKlass*)NULL)))))
{
(is_default ||
can_be_overridden(super_method, target_loader, target_classname) ||
(klass->major_version() >= VTABLE_TRANSITIVE_OVERRIDE_VERSION &&
(super_klass = find_transitive_override(super_klass,
target_method, i, target_loader,
target_classname)) != NULL))) {
// Package private methods always need a new entry to root their own
// overriding. They may also override other methods.
if (!target_method()->is_package_private()) {
if (!target_method->is_package_private()) {
allocate_new = false;
}
// Do not check loader constraints for overpass methods because overpass
// methods are created by the jvm to throw exceptions.
if (checkconstraints && !target_method()->is_overpass()) {
if (checkconstraints && !target_method->is_overpass()) {
// Override vtable entry if passes loader constraint check
// if loader constraint checking requested
// No need to visit his super, since he and his super
@ -498,7 +515,7 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, const methodHand
stringStream ss;
ss.print("loader constraint violation for class %s: when selecting "
"overriding method '", klass->external_name());
target_method()->print_external_name(&ss),
target_method->print_external_name(&ss),
ss.print("' the class loader %s of the "
"selected method's type %s, and the class loader %s for its super "
"type %s have different Class objects for the type %s used in the signature (%s; %s)",
@ -517,7 +534,7 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, const methodHand
put_method_at(target_method(), i);
overrides = true;
if (!is_default) {
target_method()->set_vtable_index(i);
target_method->set_vtable_index(i);
} else {
if (def_vtable_indices != NULL) {
if (is_preinitialized_vtable()) {
@ -544,6 +561,7 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, const methodHand
void klassVtable::put_method_at(Method* m, int index) {
assert(!m->is_private(), "private methods should not be in vtable");
JVMTI_ONLY(assert(!m->is_old() || ik()->is_being_redefined(), "old methods should not be in vtable"));
if (is_preinitialized_vtable()) {
// At runtime initialize_vtable is rerun as part of link_class_impl()
// for shared class loaded by the non-boot loader to obtain the loader
@ -576,13 +594,12 @@ void klassVtable::put_method_at(Method* m, int index) {
// superclass has been loaded.
// However, the vtable entries are filled in at link time, and therefore
// the superclass' vtable may not yet have been filled in.
bool klassVtable::needs_new_vtable_entry(const methodHandle& target_method,
bool klassVtable::needs_new_vtable_entry(Method* target_method,
const Klass* super,
Handle classloader,
Symbol* classname,
AccessFlags class_flags,
u2 major_version,
TRAPS) {
u2 major_version) {
if (class_flags.is_interface()) {
// Interfaces do not use vtables, except for java.lang.Object methods,
// so there is no point to assigning
@ -595,11 +612,11 @@ bool klassVtable::needs_new_vtable_entry(const methodHandle& target_method,
// a final method never needs a new entry; final methods can be statically
// resolved and they have to be present in the vtable only if they override
// a super's method, in which case they re-use its entry
(target_method()->is_private()) ||
(target_method->is_private()) ||
// private methods don't need to be in vtable
(target_method()->is_static()) ||
(target_method->is_static()) ||
// static methods don't need to be in vtable
(target_method()->name()->fast_compare(vmSymbols::object_initializer_name()) == 0)
(target_method->name()->fast_compare(vmSymbols::object_initializer_name()) == 0)
// <init> is never called dynamically-bound
) {
return false;
@ -607,10 +624,10 @@ bool klassVtable::needs_new_vtable_entry(const methodHandle& target_method,
// Concrete interface methods do not need new entries, they override
// abstract method entries using default inheritance rules
if (target_method()->method_holder() != NULL &&
target_method()->method_holder()->is_interface() &&
!target_method()->is_abstract()) {
assert(target_method()->is_default_method(),
if (target_method->method_holder() != NULL &&
target_method->method_holder()->is_interface() &&
!target_method->is_abstract()) {
assert(target_method->is_default_method(),
"unexpected interface method type");
return false;
}
@ -622,15 +639,14 @@ bool klassVtable::needs_new_vtable_entry(const methodHandle& target_method,
// Package private methods always need a new entry to root their own
// overriding. This allows transitive overriding to work.
if (target_method()->is_package_private()) {
if (target_method->is_package_private()) {
return true;
}
// search through the super class hierarchy to see if we need
// a new entry
ResourceMark rm(THREAD);
Symbol* name = target_method()->name();
Symbol* signature = target_method()->signature();
Symbol* name = target_method->name();
Symbol* signature = target_method->signature();
const Klass* k = super;
Method* super_method = NULL;
InstanceKlass *holder = NULL;
@ -643,7 +659,6 @@ bool klassVtable::needs_new_vtable_entry(const methodHandle& target_method,
break; // we still have to search for a matching miranda method
}
// get the class holding the matching method
// make sure you use that class for is_override
InstanceKlass* superk = super_method->method_holder();
// we want only instance method matches
// ignore private methods found via lookup_method since they do not participate in overriding,
@ -651,11 +666,11 @@ bool klassVtable::needs_new_vtable_entry(const methodHandle& target_method,
// ignore private, c.m pub does override a.m pub
// For classes that were not javac'd together, we also do transitive overriding around
// methods that have less accessibility
if ((!super_method->is_static()) &&
(!super_method->is_private())) {
if (superk->is_override(methodHandle(THREAD, super_method), classloader, classname, THREAD)) {
if (!super_method->is_static() &&
!super_method->is_private()) {
if (can_be_overridden(super_method, classloader, classname)) {
return false;
// else keep looking for transitive overrides
// else keep looking for transitive overrides
}
// If we get here then one of the super classes has a package private method
// that will not get overridden because it is in a different package. But,
@ -718,13 +733,12 @@ int klassVtable::index_of_miranda(Symbol* name, Symbol* signature) {
// requires that method m at entry be declared ("held") by an interface.
bool klassVtable::is_miranda_entry_at(int i) {
Method* m = method_at(i);
Klass* method_holder = m->method_holder();
InstanceKlass *mhk = InstanceKlass::cast(method_holder);
InstanceKlass* holder = m->method_holder();
// miranda methods are public abstract instance interface methods in a class's vtable
if (mhk->is_interface()) {
if (holder->is_interface()) {
assert(m->is_public(), "should be public");
assert(ik()->implements_interface(method_holder) , "this class should implement the interface");
assert(ik()->implements_interface(holder) , "this class should implement the interface");
if (is_miranda(m, ik()->methods(), ik()->default_methods(), ik()->super(), klass()->is_interface())) {
return true;
}
@ -888,7 +902,7 @@ void klassVtable::get_mirandas(GrowableArray<Method*>* new_mirandas,
// iterate thru the local interfaces looking for a miranda
int num_local_ifs = local_interfaces->length();
for (int i = 0; i < num_local_ifs; i++) {
InstanceKlass *ik = InstanceKlass::cast(local_interfaces->at(i));
InstanceKlass *ik = local_interfaces->at(i);
add_new_mirandas_to_lists(new_mirandas, all_mirandas,
ik->methods(), class_methods,
default_methods, super, is_interface);
@ -1107,9 +1121,9 @@ void klassItable::initialize_itable(bool checkconstraints, TRAPS) {
for(i = 0; i < num_interfaces; i++) {
itableOffsetEntry* ioe = offset_entry(i);
HandleMark hm(THREAD);
Klass* interf = ioe->interface_klass();
InstanceKlass* interf = ioe->interface_klass();
assert(interf != NULL && ioe->offset() != 0, "bad offset entry in itable");
initialize_itable_for_interface(ioe->offset(), InstanceKlass::cast(interf), checkconstraints, CHECK);
initialize_itable_for_interface(ioe->offset(), interf, checkconstraints, CHECK);
}
}

View File

@ -109,17 +109,20 @@ class klassVtable {
void copy_vtable_to(vtableEntry* start);
int initialize_from_super(Klass* super);
void put_method_at(Method* m, int index);
static bool needs_new_vtable_entry(const methodHandle& m,
static bool needs_new_vtable_entry(Method* m,
const Klass* super,
Handle classloader,
Symbol* classname,
AccessFlags access_flags,
u2 major_version,
TRAPS);
u2 major_version);
bool update_inherited_vtable(InstanceKlass* klass, const methodHandle& target_method, int super_vtable_len, int default_index, bool checkconstraints, TRAPS);
InstanceKlass* find_transitive_override(InstanceKlass* initialsuper, const methodHandle& target_method, int vtable_index,
Handle target_loader, Symbol* target_classname, Thread* THREAD);
bool update_inherited_vtable(const methodHandle& target_method,
int super_vtable_len,
int default_index,
bool checkconstraints, TRAPS);
InstanceKlass* find_transitive_override(InstanceKlass* initialsuper,
const methodHandle& target_method, int vtable_index,
Handle target_loader, Symbol* target_classname);
// support for miranda methods
bool is_miranda_entry_at(int i);