8009130: Lambda: Fix access controls, loader constraints

New default methods list with inherited superinterface methods

Reviewed-by: minqi, sspitsyn, coleenp
This commit is contained in:
Karen Kinnear 2013-10-07 12:20:28 -04:00
parent 2b82651ec0
commit 088ded71f9
18 changed files with 662 additions and 248 deletions

View file

@ -4080,8 +4080,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
// Generate any default methods - default methods are interface methods // Generate any default methods - default methods are interface methods
// that have a default implementation. This is new with Lambda project. // that have a default implementation. This is new with Lambda project.
if (has_default_methods && !access_flags.is_interface() && if (has_default_methods && !access_flags.is_interface() ) {
local_interfaces->length() > 0) {
DefaultMethods::generate_default_methods( DefaultMethods::generate_default_methods(
this_klass(), &all_mirandas, CHECK_(nullHandle)); this_klass(), &all_mirandas, CHECK_(nullHandle));
} }

View file

@ -345,7 +345,6 @@ class MethodFamily : public ResourceObj {
} }
Symbol* generate_no_defaults_message(TRAPS) const; Symbol* generate_no_defaults_message(TRAPS) const;
Symbol* generate_abstract_method_message(Method* method, TRAPS) const;
Symbol* generate_conflicts_message(GrowableArray<Method*>* methods, TRAPS) const; Symbol* generate_conflicts_message(GrowableArray<Method*>* methods, TRAPS) const;
public: public:
@ -404,20 +403,19 @@ class MethodFamily : public ResourceObj {
_exception_message = generate_no_defaults_message(CHECK); _exception_message = generate_no_defaults_message(CHECK);
_exception_name = vmSymbols::java_lang_AbstractMethodError(); _exception_name = vmSymbols::java_lang_AbstractMethodError();
} else if (qualified_methods.length() == 1) { } else if (qualified_methods.length() == 1) {
// leave abstract methods alone, they will be found via normal search path
Method* method = qualified_methods.at(0); Method* method = qualified_methods.at(0);
if (method->is_abstract()) { if (!method->is_abstract()) {
_exception_message = generate_abstract_method_message(method, CHECK);
_exception_name = vmSymbols::java_lang_AbstractMethodError();
} else {
_selected_target = qualified_methods.at(0); _selected_target = qualified_methods.at(0);
} }
} else { } else {
_exception_message = generate_conflicts_message(&qualified_methods,CHECK); _exception_message = generate_conflicts_message(&qualified_methods,CHECK);
_exception_name = vmSymbols::java_lang_IncompatibleClassChangeError(); _exception_name = vmSymbols::java_lang_IncompatibleClassChangeError();
if (TraceDefaultMethods) {
_exception_message->print_value_on(tty);
tty->print_cr("");
}
} }
assert((has_target() ^ throws_exception()) == 1,
"One and only one must be true");
} }
bool contains_signature(Symbol* query) { bool contains_signature(Symbol* query) {
@ -475,20 +473,6 @@ Symbol* MethodFamily::generate_no_defaults_message(TRAPS) const {
return SymbolTable::new_symbol("No qualifying defaults found", CHECK_NULL); return SymbolTable::new_symbol("No qualifying defaults found", CHECK_NULL);
} }
Symbol* MethodFamily::generate_abstract_method_message(Method* method, TRAPS) const {
Symbol* klass = method->klass_name();
Symbol* name = method->name();
Symbol* sig = method->signature();
stringStream ss;
ss.print("Method ");
ss.write((const char*)klass->bytes(), klass->utf8_length());
ss.print(".");
ss.write((const char*)name->bytes(), name->utf8_length());
ss.write((const char*)sig->bytes(), sig->utf8_length());
ss.print(" is abstract");
return SymbolTable::new_symbol(ss.base(), (int)ss.size(), CHECK_NULL);
}
Symbol* MethodFamily::generate_conflicts_message(GrowableArray<Method*>* methods, TRAPS) const { Symbol* MethodFamily::generate_conflicts_message(GrowableArray<Method*>* methods, TRAPS) const {
stringStream ss; stringStream ss;
ss.print("Conflicting default methods:"); ss.print("Conflicting default methods:");
@ -595,6 +579,18 @@ class EmptyVtableSlot : public ResourceObj {
#endif // ndef PRODUCT #endif // ndef PRODUCT
}; };
static bool already_in_vtable_slots(GrowableArray<EmptyVtableSlot*>* slots, Method* m) {
bool found = false;
for (int j = 0; j < slots->length(); ++j) {
if (slots->at(j)->name() == m->name() &&
slots->at(j)->signature() == m->signature() ) {
found = true;
break;
}
}
return found;
}
static GrowableArray<EmptyVtableSlot*>* find_empty_vtable_slots( static GrowableArray<EmptyVtableSlot*>* find_empty_vtable_slots(
InstanceKlass* klass, GrowableArray<Method*>* mirandas, TRAPS) { InstanceKlass* klass, GrowableArray<Method*>* mirandas, TRAPS) {
@ -604,8 +600,10 @@ static GrowableArray<EmptyVtableSlot*>* find_empty_vtable_slots(
// All miranda methods are obvious candidates // All miranda methods are obvious candidates
for (int i = 0; i < mirandas->length(); ++i) { for (int i = 0; i < mirandas->length(); ++i) {
EmptyVtableSlot* slot = new EmptyVtableSlot(mirandas->at(i)); Method* m = mirandas->at(i);
slots->append(slot); if (!already_in_vtable_slots(slots, m)) {
slots->append(new EmptyVtableSlot(m));
}
} }
// Also any overpasses in our superclasses, that we haven't implemented. // Also any overpasses in our superclasses, that we haven't implemented.
@ -621,7 +619,26 @@ static GrowableArray<EmptyVtableSlot*>* find_empty_vtable_slots(
// unless we have a real implementation of it in the current class. // unless we have a real implementation of it in the current class.
Method* impl = klass->lookup_method(m->name(), m->signature()); Method* impl = klass->lookup_method(m->name(), m->signature());
if (impl == NULL || impl->is_overpass()) { if (impl == NULL || impl->is_overpass()) {
slots->append(new EmptyVtableSlot(m)); if (!already_in_vtable_slots(slots, m)) {
slots->append(new EmptyVtableSlot(m));
}
}
}
}
// also any default methods in our superclasses
if (super->default_methods() != NULL) {
for (int i = 0; i < super->default_methods()->length(); ++i) {
Method* m = super->default_methods()->at(i);
// m is a method that would have been a miranda if not for the
// default method processing that occurred on behalf of our superclass,
// so it's a method we want to re-examine in this new context. That is,
// unless we have a real implementation of it in the current class.
Method* impl = klass->lookup_method(m->name(), m->signature());
if (impl == NULL || impl->is_overpass()) {
if (!already_in_vtable_slots(slots, m)) {
slots->append(new EmptyVtableSlot(m));
}
} }
} }
} }
@ -679,7 +696,7 @@ class FindMethodsByErasedSig : public HierarchyVisitor<FindMethodsByErasedSig> {
// private interface methods are not candidates for default methods // private interface methods are not candidates for default methods
// invokespecial to private interface methods doesn't use default method logic // invokespecial to private interface methods doesn't use default method logic
// future: take access controls into account for superclass methods // future: take access controls into account for superclass methods
if (m != NULL && (!iklass->is_interface() || m->is_public())) { if (m != NULL && !m->is_static() && (!iklass->is_interface() || m->is_public())) {
if (_family == NULL) { if (_family == NULL) {
_family = new StatefulMethodFamily(); _family = new StatefulMethodFamily();
} }
@ -700,7 +717,7 @@ class FindMethodsByErasedSig : public HierarchyVisitor<FindMethodsByErasedSig> {
static void create_overpasses( static void create_defaults_and_exceptions(
GrowableArray<EmptyVtableSlot*>* slots, InstanceKlass* klass, TRAPS); GrowableArray<EmptyVtableSlot*>* slots, InstanceKlass* klass, TRAPS);
static void generate_erased_defaults( static void generate_erased_defaults(
@ -721,6 +738,8 @@ static void generate_erased_defaults(
static void merge_in_new_methods(InstanceKlass* klass, static void merge_in_new_methods(InstanceKlass* klass,
GrowableArray<Method*>* new_methods, TRAPS); GrowableArray<Method*>* new_methods, TRAPS);
static void create_default_methods( InstanceKlass* klass,
GrowableArray<Method*>* new_methods, TRAPS);
// This is the guts of the default methods implementation. This is called just // This is the guts of the default methods implementation. This is called just
// after the classfile has been parsed if some ancestor has default methods. // after the classfile has been parsed if some ancestor has default methods.
@ -782,7 +801,7 @@ void DefaultMethods::generate_default_methods(
} }
#endif // ndef PRODUCT #endif // ndef PRODUCT
create_overpasses(empty_slots, klass, CHECK); create_defaults_and_exceptions(empty_slots, klass, CHECK);
#ifndef PRODUCT #ifndef PRODUCT
if (TraceDefaultMethods) { if (TraceDefaultMethods) {
@ -791,66 +810,6 @@ void DefaultMethods::generate_default_methods(
#endif // ndef PRODUCT #endif // ndef PRODUCT
} }
#ifdef ASSERT
// Return true is broad type is a covariant return of narrow type
static bool covariant_return_type(BasicType narrow, BasicType broad) {
if (narrow == broad) {
return true;
}
if (broad == T_OBJECT) {
return true;
}
return false;
}
#endif
static int assemble_redirect(
BytecodeConstantPool* cp, BytecodeBuffer* buffer,
Symbol* incoming, Method* target, TRAPS) {
BytecodeAssembler assem(buffer, cp);
SignatureStream in(incoming, true);
SignatureStream out(target->signature(), true);
u2 parameter_count = 0;
assem.aload(parameter_count++); // load 'this'
while (!in.at_return_type()) {
assert(!out.at_return_type(), "Parameter counts do not match");
BasicType bt = in.type();
assert(out.type() == bt, "Parameter types are not compatible");
assem.load(bt, parameter_count);
if (in.is_object() && in.as_symbol(THREAD) != out.as_symbol(THREAD)) {
assem.checkcast(out.as_symbol(THREAD));
} else if (bt == T_LONG || bt == T_DOUBLE) {
++parameter_count; // longs and doubles use two slots
}
++parameter_count;
in.next();
out.next();
}
assert(out.at_return_type(), "Parameter counts do not match");
assert(covariant_return_type(out.type(), in.type()), "Return types are not compatible");
if (parameter_count == 1 && (in.type() == T_LONG || in.type() == T_DOUBLE)) {
++parameter_count; // need room for return value
}
if (target->method_holder()->is_interface()) {
assem.invokespecial(target);
} else {
assem.invokevirtual(target);
}
if (in.is_object() && in.as_symbol(THREAD) != out.as_symbol(THREAD)) {
assem.checkcast(in.as_symbol(THREAD));
}
assem._return(in.type());
return parameter_count;
}
static int assemble_method_error( static int assemble_method_error(
BytecodeConstantPool* cp, BytecodeBuffer* buffer, Symbol* errorName, Symbol* message, TRAPS) { BytecodeConstantPool* cp, BytecodeBuffer* buffer, Symbol* errorName, Symbol* message, TRAPS) {
@ -924,18 +883,18 @@ static void switchover_constant_pool(BytecodeConstantPool* bpool,
} }
} }
// A "bridge" is a method created by javac to bridge the gap between // Create default_methods list for the current class.
// an implementation and a generically-compatible, but different, signature. // With the VM only processing erased signatures, the VM only
// Bridges have actual bytecode implementation in classfiles. // creates an overpass in a conflict case or a case with no candidates.
// An "overpass", on the other hand, performs the same function as a bridge // This allows virtual methods to override the overpass, but ensures
// but does not occur in a classfile; the VM creates overpass itself, // that a local method search will find the exception rather than an abstract
// when it needs a path to get from a call site to an default method, and // or default method that is not a valid candidate.
// a bridge doesn't exist. static void create_defaults_and_exceptions(
static void create_overpasses(
GrowableArray<EmptyVtableSlot*>* slots, GrowableArray<EmptyVtableSlot*>* slots,
InstanceKlass* klass, TRAPS) { InstanceKlass* klass, TRAPS) {
GrowableArray<Method*> overpasses; GrowableArray<Method*> overpasses;
GrowableArray<Method*> defaults;
BytecodeConstantPool bpool(klass->constants()); BytecodeConstantPool bpool(klass->constants());
for (int i = 0; i < slots->length(); ++i) { for (int i = 0; i < slots->length(); ++i) {
@ -943,7 +902,6 @@ static void create_overpasses(
if (slot->is_bound()) { if (slot->is_bound()) {
MethodFamily* method = slot->get_binding(); MethodFamily* method = slot->get_binding();
int max_stack = 0;
BytecodeBuffer buffer; BytecodeBuffer buffer;
#ifndef PRODUCT #ifndef PRODUCT
@ -953,26 +911,27 @@ static void create_overpasses(
tty->print_cr(""); tty->print_cr("");
if (method->has_target()) { if (method->has_target()) {
method->print_selected(tty, 1); method->print_selected(tty, 1);
} else { } else if (method->throws_exception()) {
method->print_exception(tty, 1); method->print_exception(tty, 1);
} }
} }
#endif // ndef PRODUCT #endif // ndef PRODUCT
if (method->has_target()) { if (method->has_target()) {
Method* selected = method->get_selected_target(); Method* selected = method->get_selected_target();
if (selected->method_holder()->is_interface()) { if (selected->method_holder()->is_interface()) {
max_stack = assemble_redirect( defaults.push(selected);
&bpool, &buffer, slot->signature(), selected, CHECK);
} }
} else if (method->throws_exception()) { } else if (method->throws_exception()) {
max_stack = assemble_method_error(&bpool, &buffer, method->get_exception_name(), method->get_exception_message(), CHECK); int max_stack = assemble_method_error(&bpool, &buffer,
} method->get_exception_name(), method->get_exception_message(), CHECK);
if (max_stack != 0) {
AccessFlags flags = accessFlags_from( AccessFlags flags = accessFlags_from(
JVM_ACC_PUBLIC | JVM_ACC_SYNTHETIC | JVM_ACC_BRIDGE); JVM_ACC_PUBLIC | JVM_ACC_SYNTHETIC | JVM_ACC_BRIDGE);
Method* m = new_method(&bpool, &buffer, slot->name(), slot->signature(), Method* m = new_method(&bpool, &buffer, slot->name(), slot->signature(),
flags, max_stack, slot->size_of_parameters(), flags, max_stack, slot->size_of_parameters(),
ConstMethod::OVERPASS, CHECK); ConstMethod::OVERPASS, CHECK);
// We push to the methods list:
// overpass methods which are exception throwing methods
if (m != NULL) { if (m != NULL) {
overpasses.push(m); overpasses.push(m);
} }
@ -983,11 +942,31 @@ static void create_overpasses(
#ifndef PRODUCT #ifndef PRODUCT
if (TraceDefaultMethods) { if (TraceDefaultMethods) {
tty->print_cr("Created %d overpass methods", overpasses.length()); tty->print_cr("Created %d overpass methods", overpasses.length());
tty->print_cr("Created %d default methods", defaults.length());
} }
#endif // ndef PRODUCT #endif // ndef PRODUCT
switchover_constant_pool(&bpool, klass, &overpasses, CHECK); if (overpasses.length() > 0) {
merge_in_new_methods(klass, &overpasses, CHECK); switchover_constant_pool(&bpool, klass, &overpasses, CHECK);
merge_in_new_methods(klass, &overpasses, CHECK);
}
if (defaults.length() > 0) {
create_default_methods(klass, &defaults, CHECK);
}
}
static void create_default_methods( InstanceKlass* klass,
GrowableArray<Method*>* new_methods, TRAPS) {
int new_size = new_methods->length();
Array<Method*>* total_default_methods = MetadataFactory::new_array<Method*>(
klass->class_loader_data(), new_size, NULL, CHECK);
for (int index = 0; index < new_size; index++ ) {
total_default_methods->at_put(index, new_methods->at(index));
}
Method::sort_methods(total_default_methods, false, false);
klass->set_default_methods(total_default_methods);
} }
static void sort_methods(GrowableArray<Method*>* methods) { static void sort_methods(GrowableArray<Method*>* methods) {

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -812,8 +812,8 @@ class ClassHierarchyWalker {
Klass* k = ctxk; Klass* k = ctxk;
Method* lm = k->lookup_method(m->name(), m->signature()); Method* lm = k->lookup_method(m->name(), m->signature());
if (lm == NULL && k->oop_is_instance()) { if (lm == NULL && k->oop_is_instance()) {
// It might be an abstract interface method, devoid of mirandas. // It might be an interface method
lm = ((InstanceKlass*)k)->lookup_method_in_all_interfaces(m->name(), lm = ((InstanceKlass*)k)->lookup_method_in_ordered_interfaces(m->name(),
m->signature()); m->signature());
} }
if (lm == m) if (lm == m)

View file

@ -1,4 +1,5 @@
/* /*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -221,8 +222,17 @@ void LinkResolver::resolve_klass(KlassHandle& result, constantPoolHandle pool, i
// //
// According to JVM spec. $5.4.3c & $5.4.3d // According to JVM spec. $5.4.3c & $5.4.3d
// Look up method in klasses, including static methods
// Then look up local default methods
void LinkResolver::lookup_method_in_klasses(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) { void LinkResolver::lookup_method_in_klasses(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) {
Method* result_oop = klass->uncached_lookup_method(name, signature); Method* result_oop = klass->uncached_lookup_method(name, signature);
if (result_oop == NULL) {
Array<Method*>* default_methods = InstanceKlass::cast(klass())->default_methods();
if (default_methods != NULL) {
result_oop = InstanceKlass::find_method(default_methods, name, signature);
}
}
if (EnableInvokeDynamic && result_oop != NULL) { if (EnableInvokeDynamic && result_oop != NULL) {
vmIntrinsics::ID iid = result_oop->intrinsic_id(); vmIntrinsics::ID iid = result_oop->intrinsic_id();
if (MethodHandles::is_signature_polymorphic(iid)) { if (MethodHandles::is_signature_polymorphic(iid)) {
@ -234,6 +244,7 @@ void LinkResolver::lookup_method_in_klasses(methodHandle& result, KlassHandle kl
} }
// returns first instance method // returns first instance method
// Looks up method in classes, then looks up local default methods
void LinkResolver::lookup_instance_method_in_klasses(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) { void LinkResolver::lookup_instance_method_in_klasses(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) {
Method* result_oop = klass->uncached_lookup_method(name, signature); Method* result_oop = klass->uncached_lookup_method(name, signature);
result = methodHandle(THREAD, result_oop); result = methodHandle(THREAD, result_oop);
@ -241,13 +252,38 @@ void LinkResolver::lookup_instance_method_in_klasses(methodHandle& result, Klass
klass = KlassHandle(THREAD, result->method_holder()->super()); klass = KlassHandle(THREAD, result->method_holder()->super());
result = methodHandle(THREAD, klass->uncached_lookup_method(name, signature)); result = methodHandle(THREAD, klass->uncached_lookup_method(name, signature));
} }
if (result.is_null()) {
Array<Method*>* default_methods = InstanceKlass::cast(klass())->default_methods();
if (default_methods != NULL) {
result = methodHandle(InstanceKlass::find_method(default_methods, name, signature));
assert(result.is_null() || !result->is_static(), "static defaults not allowed");
}
}
} }
int LinkResolver::vtable_index_of_interface_method(KlassHandle klass,
methodHandle resolved_method, TRAPS) {
int LinkResolver::vtable_index_of_miranda_method(KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) { int vtable_index = Method::invalid_vtable_index;
ResourceMark rm(THREAD); Symbol* name = resolved_method->name();
klassVtable *vt = InstanceKlass::cast(klass())->vtable(); Symbol* signature = resolved_method->signature();
return vt->index_of_miranda(name, signature);
// 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);
if (index >= 0 ) {
vtable_index = InstanceKlass::cast(klass())->default_vtable_indices()->at(index);
}
}
if (vtable_index == Method::invalid_vtable_index) {
// get vtable_index for miranda methods
ResourceMark rm(THREAD);
klassVtable *vt = InstanceKlass::cast(klass())->vtable();
vtable_index = vt->index_of_miranda(name, signature);
}
return vtable_index;
} }
void LinkResolver::lookup_method_in_interfaces(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) { void LinkResolver::lookup_method_in_interfaces(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) {
@ -625,6 +661,12 @@ void LinkResolver::resolve_interface_method(methodHandle& resolved_method,
resolved_method->method_holder()->internal_name() resolved_method->method_holder()->internal_name()
); );
resolved_method->access_flags().print_on(tty); resolved_method->access_flags().print_on(tty);
if (resolved_method->is_default_method()) {
tty->print("default");
}
if (resolved_method->is_overpass()) {
tty->print("overpass");
}
tty->cr(); tty->cr();
} }
} }
@ -853,6 +895,7 @@ void LinkResolver::linktime_resolve_special_method(methodHandle& resolved_method
resolved_method->signature())); resolved_method->signature()));
THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
} }
if (TraceItables && Verbose) { if (TraceItables && Verbose) {
ResourceMark rm(THREAD); ResourceMark rm(THREAD);
tty->print("invokespecial resolved method: caller-class:%s, compile-time-class:%s, method:%s, method_holder:%s, access_flags: ", tty->print("invokespecial resolved method: caller-class:%s, compile-time-class:%s, method:%s, method_holder:%s, access_flags: ",
@ -864,8 +907,7 @@ void LinkResolver::linktime_resolve_special_method(methodHandle& resolved_method
resolved_method->method_holder()->internal_name() resolved_method->method_holder()->internal_name()
); );
resolved_method->access_flags().print_on(tty); resolved_method->access_flags().print_on(tty);
if (resolved_method->method_holder()->is_interface() && if (resolved_method->is_default_method()) {
!resolved_method->is_abstract()) {
tty->print("default"); tty->print("default");
} }
if (resolved_method->is_overpass()) { if (resolved_method->is_overpass()) {
@ -945,10 +987,12 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result, methodHandle
sel_method->method_holder()->internal_name() sel_method->method_holder()->internal_name()
); );
sel_method->access_flags().print_on(tty); sel_method->access_flags().print_on(tty);
if (sel_method->method_holder()->is_interface() && if (sel_method->is_default_method()) {
!sel_method->is_abstract()) {
tty->print("default"); tty->print("default");
} }
if (sel_method->is_overpass()) {
tty->print("overpass");
}
tty->cr(); tty->cr();
} }
@ -996,26 +1040,25 @@ void LinkResolver::linktime_resolve_virtual_method(methodHandle &resolved_method
THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
} }
if (PrintVtables && Verbose) { if (PrintVtables && Verbose) {
ResourceMark rm(THREAD); ResourceMark rm(THREAD);
tty->print("invokevirtual resolved method: caller-class:%s, compile-time-class:%s, method:%s, method_holder:%s, access_flags: ", tty->print("invokevirtual resolved method: caller-class:%s, compile-time-class:%s, method:%s, method_holder:%s, access_flags: ",
(current_klass.is_null() ? "<NULL>" : current_klass->internal_name()), (current_klass.is_null() ? "<NULL>" : current_klass->internal_name()),
(resolved_klass.is_null() ? "<NULL>" : resolved_klass->internal_name()), (resolved_klass.is_null() ? "<NULL>" : resolved_klass->internal_name()),
Method::name_and_sig_as_C_string(resolved_klass(), Method::name_and_sig_as_C_string(resolved_klass(),
resolved_method->name(), resolved_method->name(),
resolved_method->signature()), resolved_method->signature()),
resolved_method->method_holder()->internal_name() resolved_method->method_holder()->internal_name()
); );
resolved_method->access_flags().print_on(tty); resolved_method->access_flags().print_on(tty);
if (resolved_method->method_holder()->is_interface() && if (resolved_method->is_default_method()) {
!resolved_method->is_abstract()) { tty->print("default");
tty->print("default"); }
} if (resolved_method->is_overpass()) {
if (resolved_method->is_overpass()) { tty->print("overpass");
tty->print("overpass"); }
} tty->cr();
tty->cr(); }
}
} }
// throws runtime exceptions // throws runtime exceptions
@ -1045,10 +1088,8 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result,
// do lookup based on receiver klass using the vtable index // do lookup based on receiver klass using the vtable index
if (resolved_method->method_holder()->is_interface()) { // miranda method if (resolved_method->method_holder()->is_interface()) { // miranda method
vtable_index = vtable_index_of_miranda_method(resolved_klass, vtable_index = vtable_index_of_interface_method(resolved_klass,
resolved_method->name(), resolved_method, CHECK);
resolved_method->signature(), CHECK);
assert(vtable_index >= 0 , "we should have valid vtable index at this point"); assert(vtable_index >= 0 , "we should have valid vtable index at this point");
InstanceKlass* inst = InstanceKlass::cast(recv_klass()); InstanceKlass* inst = InstanceKlass::cast(recv_klass());
@ -1104,11 +1145,10 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result,
vtable_index vtable_index
); );
selected_method->access_flags().print_on(tty); selected_method->access_flags().print_on(tty);
if (selected_method->method_holder()->is_interface() && if (selected_method->is_default_method()) {
!selected_method->is_abstract()) {
tty->print("default"); tty->print("default");
} }
if (resolved_method->is_overpass()) { if (selected_method->is_overpass()) {
tty->print("overpass"); tty->print("overpass");
} }
tty->cr(); tty->cr();
@ -1191,7 +1231,6 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, methodHand
sel_method->name(), sel_method->name(),
sel_method->signature())); sel_method->signature()));
} }
// check if abstract // check if abstract
if (check_null_and_abstract && sel_method->is_abstract()) { if (check_null_and_abstract && sel_method->is_abstract()) {
ResourceMark rm(THREAD); ResourceMark rm(THREAD);
@ -1220,11 +1259,10 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, methodHand
sel_method->method_holder()->internal_name() sel_method->method_holder()->internal_name()
); );
sel_method->access_flags().print_on(tty); sel_method->access_flags().print_on(tty);
if (sel_method->method_holder()->is_interface() && if (sel_method->is_default_method()) {
!sel_method->is_abstract()) {
tty->print("default"); tty->print("default");
} }
if (resolved_method->is_overpass()) { if (sel_method->is_overpass()) {
tty->print("overpass"); tty->print("overpass");
} }
tty->cr(); tty->cr();

View file

@ -130,8 +130,7 @@ class LinkResolver: AllStatic {
static void lookup_polymorphic_method (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, static void lookup_polymorphic_method (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature,
KlassHandle current_klass, Handle *appendix_result_or_null, Handle *method_type_result, TRAPS); KlassHandle current_klass, Handle *appendix_result_or_null, Handle *method_type_result, TRAPS);
static int vtable_index_of_miranda_method(KlassHandle klass, Symbol* name, Symbol* signature, TRAPS); static int vtable_index_of_interface_method(KlassHandle klass, methodHandle resolved_method, TRAPS);
static void resolve_klass (KlassHandle& result, constantPoolHandle pool, int index, TRAPS); static void resolve_klass (KlassHandle& result, constantPoolHandle pool, int index, TRAPS);
static void resolve_pool (KlassHandle& resolved_klass, Symbol*& method_name, Symbol*& method_signature, KlassHandle& current_klass, constantPoolHandle pool, int index, TRAPS); static void resolve_pool (KlassHandle& resolved_klass, Symbol*& method_name, Symbol*& method_signature, KlassHandle& current_klass, constantPoolHandle pool, int index, TRAPS);

View file

@ -73,6 +73,10 @@
"Number of bytes used by the InstanceKlass::methods() array") \ "Number of bytes used by the InstanceKlass::methods() array") \
f(method_ordering_bytes, IK_method_ordering, \ f(method_ordering_bytes, IK_method_ordering, \
"Number of bytes used by the InstanceKlass::method_ordering() array") \ "Number of bytes used by the InstanceKlass::method_ordering() array") \
f(default_methods_array_bytes, IK_default_methods, \
"Number of bytes used by the InstanceKlass::default_methods() array") \
f(default_vtable_indices_bytes, IK_default_vtable_indices, \
"Number of bytes used by the InstanceKlass::default_vtable_indices() array") \
f(local_interfaces_bytes, IK_local_interfaces, \ f(local_interfaces_bytes, IK_local_interfaces, \
"Number of bytes used by the InstanceKlass::local_interfaces() array") \ "Number of bytes used by the InstanceKlass::local_interfaces() array") \
f(transitive_interfaces_bytes, IK_transitive_interfaces, \ f(transitive_interfaces_bytes, IK_transitive_interfaces, \

View file

@ -238,6 +238,13 @@ void InstanceKlass::copy_method_ordering(intArray* m, TRAPS) {
} }
} }
// create a new array of vtable_indices for default methods
Array<int>* InstanceKlass::create_new_default_vtable_indices(int len, TRAPS) {
Array<int>* vtable_indices = MetadataFactory::new_array<int>(class_loader_data(), len, CHECK_NULL);
assert(default_vtable_indices() == NULL, "only create once");
set_default_vtable_indices(vtable_indices);
return vtable_indices;
}
InstanceKlass::InstanceKlass(int vtable_len, InstanceKlass::InstanceKlass(int vtable_len,
int itable_len, int itable_len,
@ -263,6 +270,8 @@ InstanceKlass::InstanceKlass(int vtable_len,
set_array_klasses(NULL); set_array_klasses(NULL);
set_methods(NULL); set_methods(NULL);
set_method_ordering(NULL); set_method_ordering(NULL);
set_default_methods(NULL);
set_default_vtable_indices(NULL);
set_local_interfaces(NULL); set_local_interfaces(NULL);
set_transitive_interfaces(NULL); set_transitive_interfaces(NULL);
init_implementor(); init_implementor();
@ -376,6 +385,21 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) {
} }
set_method_ordering(NULL); set_method_ordering(NULL);
// default methods can be empty
if (default_methods() != NULL &&
default_methods() != Universe::the_empty_method_array()) {
MetadataFactory::free_array<Method*>(loader_data, default_methods());
}
// Do NOT deallocate the default methods, they are owned by superinterfaces.
set_default_methods(NULL);
// default methods vtable indices can be empty
if (default_vtable_indices() != NULL) {
MetadataFactory::free_array<int>(loader_data, default_vtable_indices());
}
set_default_vtable_indices(NULL);
// This array is in Klass, but remove it with the InstanceKlass since // This array is in Klass, but remove it with the InstanceKlass since
// this place would be the only caller and it can share memory with transitive // this place would be the only caller and it can share memory with transitive
// interfaces. // interfaces.
@ -1354,32 +1378,44 @@ static int binary_search(Array<Method*>* methods, Symbol* name) {
return -1; return -1;
} }
// find_method looks up the name/signature in the local methods array
Method* InstanceKlass::find_method(Symbol* name, Symbol* signature) const { Method* InstanceKlass::find_method(Symbol* name, Symbol* signature) const {
return InstanceKlass::find_method(methods(), name, signature); return InstanceKlass::find_method(methods(), name, signature);
} }
// find_method looks up the name/signature in the local methods array
Method* InstanceKlass::find_method( Method* InstanceKlass::find_method(
Array<Method*>* methods, Symbol* name, Symbol* signature) { Array<Method*>* methods, Symbol* name, Symbol* signature) {
int hit = find_method_index(methods, name, signature);
return hit >= 0 ? methods->at(hit): NULL;
}
// 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
// of the matching name/signature
int InstanceKlass::find_method_index(
Array<Method*>* methods, Symbol* name, Symbol* signature) {
int hit = binary_search(methods, name); int hit = binary_search(methods, name);
if (hit != -1) { if (hit != -1) {
Method* m = methods->at(hit); Method* m = methods->at(hit);
// Do linear search to find matching signature. First, quick check // Do linear search to find matching signature. First, quick check
// for common case // for common case
if (m->signature() == signature) return m; if (m->signature() == signature) return hit;
// search downwards through overloaded methods // search downwards through overloaded methods
int i; int i;
for (i = hit - 1; i >= 0; --i) { for (i = hit - 1; i >= 0; --i) {
Method* m = methods->at(i); Method* m = methods->at(i);
assert(m->is_method(), "must be method"); assert(m->is_method(), "must be method");
if (m->name() != name) break; if (m->name() != name) break;
if (m->signature() == signature) return m; if (m->signature() == signature) return i;
} }
// search upwards // search upwards
for (i = hit + 1; i < methods->length(); ++i) { for (i = hit + 1; i < methods->length(); ++i) {
Method* m = methods->at(i); Method* m = methods->at(i);
assert(m->is_method(), "must be method"); assert(m->is_method(), "must be method");
if (m->name() != name) break; if (m->name() != name) break;
if (m->signature() == signature) return m; if (m->signature() == signature) return i;
} }
// not found // not found
#ifdef ASSERT #ifdef ASSERT
@ -1387,9 +1423,8 @@ Method* InstanceKlass::find_method(
assert(index == -1, err_msg("binary search should have found entry %d", index)); assert(index == -1, err_msg("binary search should have found entry %d", index));
#endif #endif
} }
return NULL; return -1;
} }
int InstanceKlass::find_method_by_name(Symbol* name, int* end) { int InstanceKlass::find_method_by_name(Symbol* name, int* end) {
return find_method_by_name(methods(), name, end); return find_method_by_name(methods(), name, end);
} }
@ -1408,6 +1443,7 @@ int InstanceKlass::find_method_by_name(
return -1; return -1;
} }
// lookup_method searches both the local methods array and all superclasses methods arrays
Method* InstanceKlass::uncached_lookup_method(Symbol* name, Symbol* signature) const { Method* InstanceKlass::uncached_lookup_method(Symbol* name, Symbol* signature) const {
Klass* klass = const_cast<InstanceKlass*>(this); Klass* klass = const_cast<InstanceKlass*>(this);
while (klass != NULL) { while (klass != NULL) {
@ -1418,6 +1454,21 @@ Method* InstanceKlass::uncached_lookup_method(Symbol* name, Symbol* signature) c
return NULL; return NULL;
} }
// lookup a method in the default methods list then in all transitive interfaces
// Do NOT return private or static methods
Method* InstanceKlass::lookup_method_in_ordered_interfaces(Symbol* name,
Symbol* signature) const {
Method* m;
if (default_methods() != NULL) {
m = find_method(default_methods(), name, signature);
}
// Look up interfaces
if (m == NULL) {
m = lookup_method_in_all_interfaces(name, signature);
}
return m;
}
// lookup a method in all the interfaces that this class implements // lookup a method in all the interfaces that this class implements
// Do NOT return private or static methods, new in JDK8 which are not externally visible // Do NOT return private or static methods, new in JDK8 which are not externally visible
// They should only be found in the initial InterfaceMethodRef // They should only be found in the initial InterfaceMethodRef
@ -2548,6 +2599,42 @@ Method* InstanceKlass::method_at_itable(Klass* holder, int index, TRAPS) {
return m; return m;
} }
#if INCLUDE_JVMTI
// update default_methods for redefineclasses for methods that are
// not yet in the vtable due to concurrent subclass define and superinterface
// redefinition
// Note: those in the vtable, should have been updated via adjust_method_entries
void InstanceKlass::adjust_default_methods(Method** old_methods, Method** new_methods,
int methods_length, bool* trace_name_printed) {
// search the default_methods for uses of either obsolete or EMCP methods
if (default_methods() != NULL) {
for (int j = 0; j < methods_length; j++) {
Method* old_method = old_methods[j];
Method* new_method = new_methods[j];
for (int index = 0; index < default_methods()->length(); index ++) {
if (default_methods()->at(index) == old_method) {
default_methods()->at_put(index, new_method);
if (RC_TRACE_IN_RANGE(0x00100000, 0x00400000)) {
if (!(*trace_name_printed)) {
// RC_TRACE_MESG macro has an embedded ResourceMark
RC_TRACE_MESG(("adjust: klassname=%s default methods from name=%s",
external_name(),
old_method->method_holder()->external_name()));
*trace_name_printed = true;
}
RC_TRACE(0x00100000, ("default method update: %s(%s) ",
new_method->name()->as_C_string(),
new_method->signature()->as_C_string()));
}
}
}
}
}
}
#endif // INCLUDE_JVMTI
// On-stack replacement stuff // On-stack replacement stuff
void InstanceKlass::add_osr_nmethod(nmethod* n) { void InstanceKlass::add_osr_nmethod(nmethod* n) {
// only one compilation can be active // only one compilation can be active
@ -2742,11 +2829,21 @@ void InstanceKlass::print_on(outputStream* st) const {
st->print(BULLET"methods: "); methods()->print_value_on(st); st->cr(); st->print(BULLET"methods: "); methods()->print_value_on(st); st->cr();
if (Verbose || WizardMode) { if (Verbose || WizardMode) {
Array<Method*>* method_array = methods(); Array<Method*>* method_array = methods();
for(int i = 0; i < method_array->length(); i++) { for (int i = 0; i < method_array->length(); i++) {
st->print("%d : ", i); method_array->at(i)->print_value(); st->cr(); st->print("%d : ", i); method_array->at(i)->print_value(); st->cr();
} }
} }
st->print(BULLET"method ordering: "); method_ordering()->print_value_on(st); st->cr(); st->print(BULLET"method ordering: "); method_ordering()->print_value_on(st); st->cr();
st->print(BULLET"default_methods: "); default_methods()->print_value_on(st); st->cr();
if (Verbose && default_methods() != NULL) {
Array<Method*>* method_array = default_methods();
for (int i = 0; i < method_array->length(); i++) {
st->print("%d : ", i); method_array->at(i)->print_value(); st->cr();
}
}
if (default_vtable_indices() != NULL) {
st->print(BULLET"default vtable indices: "); default_vtable_indices()->print_value_on(st); st->cr();
}
st->print(BULLET"local interfaces: "); local_interfaces()->print_value_on(st); st->cr(); st->print(BULLET"local interfaces: "); local_interfaces()->print_value_on(st); st->cr();
st->print(BULLET"trans. interfaces: "); transitive_interfaces()->print_value_on(st); st->cr(); st->print(BULLET"trans. interfaces: "); transitive_interfaces()->print_value_on(st); st->cr();
st->print(BULLET"constants: "); constants()->print_value_on(st); st->cr(); st->print(BULLET"constants: "); constants()->print_value_on(st); st->cr();
@ -3099,6 +3196,19 @@ void InstanceKlass::verify_on(outputStream* st, bool check_dictionary) {
} }
} }
// Verify default methods
if (default_methods() != NULL) {
Array<Method*>* methods = this->default_methods();
for (int j = 0; j < methods->length(); j++) {
guarantee(methods->at(j)->is_method(), "non-method in methods array");
}
for (int j = 0; j < methods->length() - 1; j++) {
Method* m1 = methods->at(j);
Method* m2 = methods->at(j + 1);
guarantee(m1->name()->fast_compare(m2->name()) <= 0, "methods not sorted correctly");
}
}
// Verify JNI static field identifiers // Verify JNI static field identifiers
if (jni_ids() != NULL) { if (jni_ids() != NULL) {
jni_ids()->verify(this); jni_ids()->verify(this);

View file

@ -269,12 +269,18 @@ class InstanceKlass: public Klass {
// Method array. // Method array.
Array<Method*>* _methods; Array<Method*>* _methods;
// Default Method Array, concrete methods inherited from interfaces
Array<Method*>* _default_methods;
// Interface (Klass*s) this class declares locally to implement. // Interface (Klass*s) this class declares locally to implement.
Array<Klass*>* _local_interfaces; Array<Klass*>* _local_interfaces;
// Interface (Klass*s) this class implements transitively. // Interface (Klass*s) this class implements transitively.
Array<Klass*>* _transitive_interfaces; Array<Klass*>* _transitive_interfaces;
// Int array containing the original order of method in the class file (for JVMTI). // Int array containing the original order of method in the class file (for JVMTI).
Array<int>* _method_ordering; Array<int>* _method_ordering;
// Int array containing the vtable_indices for default_methods
// offset matches _default_methods offset
Array<int>* _default_vtable_indices;
// Instance and static variable information, starts with 6-tuples of shorts // Instance and static variable information, starts with 6-tuples of shorts
// [access, name index, sig index, initval index, low_offset, high_offset] // [access, name index, sig index, initval index, low_offset, high_offset]
// for all fields, followed by the generic signature data at the end of // for all fields, followed by the generic signature data at the end of
@ -356,6 +362,15 @@ class InstanceKlass: public Klass {
void set_method_ordering(Array<int>* m) { _method_ordering = m; } void set_method_ordering(Array<int>* m) { _method_ordering = m; }
void copy_method_ordering(intArray* m, TRAPS); void copy_method_ordering(intArray* m, TRAPS);
// default_methods
Array<Method*>* default_methods() const { return _default_methods; }
void set_default_methods(Array<Method*>* a) { _default_methods = a; }
// default method vtable_indices
Array<int>* default_vtable_indices() const { return _default_vtable_indices; }
void set_default_vtable_indices(Array<int>* v) { _default_vtable_indices = v; }
Array<int>* create_new_default_vtable_indices(int len, TRAPS);
// interfaces // interfaces
Array<Klass*>* local_interfaces() const { return _local_interfaces; } Array<Klass*>* local_interfaces() const { return _local_interfaces; }
void set_local_interfaces(Array<Klass*>* a) { void set_local_interfaces(Array<Klass*>* a) {
@ -501,12 +516,18 @@ class InstanceKlass: public Klass {
Method* find_method(Symbol* name, Symbol* signature) const; Method* find_method(Symbol* name, Symbol* signature) const;
static Method* find_method(Array<Method*>* methods, Symbol* name, Symbol* signature); static Method* find_method(Array<Method*>* methods, Symbol* name, Symbol* signature);
// 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);
// lookup operation (returns NULL if not found) // lookup operation (returns NULL if not found)
Method* uncached_lookup_method(Symbol* name, Symbol* signature) const; Method* uncached_lookup_method(Symbol* name, Symbol* signature) const;
// lookup a method in all the interfaces that this class implements // lookup a method in all the interfaces that this class implements
// (returns NULL if not found) // (returns NULL if not found)
Method* lookup_method_in_all_interfaces(Symbol* name, Symbol* signature) const; Method* lookup_method_in_all_interfaces(Symbol* name, Symbol* signature) const;
// lookup a method in local defaults then in all interfaces
// (returns NULL if not found)
Method* lookup_method_in_ordered_interfaces(Symbol* name, Symbol* signature) const;
// Find method indices by name. If a method with the specified name is // Find method indices by name. If a method with the specified name is
// found the index to the first method is returned, and 'end' is filled in // found the index to the first method is returned, and 'end' is filled in
@ -910,6 +931,11 @@ class InstanceKlass: public Klass {
klassItable* itable() const; // return new klassItable wrapper klassItable* itable() const; // return new klassItable wrapper
Method* method_at_itable(Klass* holder, int index, TRAPS); Method* method_at_itable(Klass* holder, int index, TRAPS);
#if INCLUDE_JVMTI
void adjust_default_methods(Method** old_methods, Method** new_methods,
int methods_length, bool* trace_name_printed);
#endif // INCLUDE_JVMTI
// Garbage collection // Garbage collection
void oop_follow_contents(oop obj); void oop_follow_contents(oop obj);
int oop_adjust_pointers(oop obj); int oop_adjust_pointers(oop obj);

View file

@ -83,7 +83,7 @@ void klassVtable::compute_vtable_size_and_num_mirandas(
GrowableArray<Method*> new_mirandas(20); GrowableArray<Method*> new_mirandas(20);
// compute the number of mirandas methods that must be added to the end // compute the number of mirandas methods that must be added to the end
get_mirandas(&new_mirandas, all_mirandas, super, methods, local_interfaces); get_mirandas(&new_mirandas, all_mirandas, super, methods, NULL, local_interfaces);
*num_new_mirandas = new_mirandas.length(); *num_new_mirandas = new_mirandas.length();
vtable_length += *num_new_mirandas * vtableEntry::size(); vtable_length += *num_new_mirandas * vtableEntry::size();
@ -186,7 +186,7 @@ void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) {
assert(methods->at(i)->is_method(), "must be a Method*"); assert(methods->at(i)->is_method(), "must be a Method*");
methodHandle mh(THREAD, methods->at(i)); methodHandle mh(THREAD, methods->at(i));
bool needs_new_entry = update_inherited_vtable(ik(), mh, super_vtable_len, checkconstraints, CHECK); bool needs_new_entry = update_inherited_vtable(ik(), mh, super_vtable_len, -1, checkconstraints, CHECK);
if (needs_new_entry) { if (needs_new_entry) {
put_method_at(mh(), initialized); put_method_at(mh(), initialized);
@ -195,7 +195,35 @@ void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) {
} }
} }
// add miranda methods to end of vtable. // update vtable with default_methods
Array<Method*>* default_methods = ik()->default_methods();
if (default_methods != NULL) {
len = default_methods->length();
if (len > 0) {
Array<int>* def_vtable_indices = NULL;
if ((def_vtable_indices = ik()->default_vtable_indices()) == NULL) {
def_vtable_indices = ik()->create_new_default_vtable_indices(len, CHECK);
} else {
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));
bool needs_new_entry = update_inherited_vtable(ik(), mh, super_vtable_len, i, checkconstraints, CHECK);
// needs new entry
if (needs_new_entry) {
put_method_at(mh(), initialized);
def_vtable_indices->at_put(i, initialized); //set vtable index
initialized++;
}
}
}
}
// add miranda methods; it will also return the updated initialized
initialized = fill_in_mirandas(initialized); initialized = fill_in_mirandas(initialized);
// In class hierarchies where the accessibility is not increasing (i.e., going from private -> // In class hierarchies where the accessibility is not increasing (i.e., going from private ->
@ -230,14 +258,19 @@ InstanceKlass* klassVtable::find_transitive_override(InstanceKlass* initialsuper
#ifndef PRODUCT #ifndef PRODUCT
if (PrintVtables && Verbose) { if (PrintVtables && Verbose) {
ResourceMark rm(THREAD); ResourceMark rm(THREAD);
char* sig = target_method()->name_and_sig_as_C_string();
tty->print("transitive overriding superclass %s with %s::%s index %d, original flags: ", tty->print("transitive overriding superclass %s with %s::%s index %d, original flags: ",
supersuperklass->internal_name(), supersuperklass->internal_name(),
_klass->internal_name(), (target_method() != NULL) ? _klass->internal_name(), sig, vtable_index);
target_method()->name()->as_C_string() : "<NULL>", vtable_index);
super_method->access_flags().print_on(tty); super_method->access_flags().print_on(tty);
if (super_method->is_default_method()) {
tty->print("default");
}
tty->print("overriders flags: "); tty->print("overriders flags: ");
target_method->access_flags().print_on(tty); target_method->access_flags().print_on(tty);
tty->cr(); if (target_method->is_default_method()) {
tty->print("default");
}
} }
#endif /*PRODUCT*/ #endif /*PRODUCT*/
break; // return found superk break; // return found superk
@ -258,16 +291,31 @@ InstanceKlass* klassVtable::find_transitive_override(InstanceKlass* initialsuper
// OR return true if a new vtable entry is required. // OR return true if a new vtable entry is required.
// Only called for InstanceKlass's, i.e. not for arrays // Only called for InstanceKlass's, i.e. not for arrays
// If that changed, could not use _klass as handle for klass // If that changed, could not use _klass as handle for klass
bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle target_method, int super_vtable_len, bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle target_method,
bool checkconstraints, TRAPS) { int super_vtable_len, int default_index,
bool checkconstraints, TRAPS) {
ResourceMark rm; ResourceMark rm;
bool allocate_new = true; bool allocate_new = true;
assert(klass->oop_is_instance(), "must be InstanceKlass"); assert(klass->oop_is_instance(), "must be InstanceKlass");
assert(klass == target_method()->method_holder(), "caller resp.");
// Initialize the method's vtable index to "nonvirtual". Array<int>* def_vtable_indices = NULL;
// If we allocate a vtable entry, we will update it to a non-negative number. bool is_default = false;
target_method()->set_vtable_index(Method::nonvirtual_vtable_index); // default methods are concrete methods in superinterfaces which are added to the vtable
// with their real method_holder
// Since vtable and itable indices share the same storage, don't touch
// the default method's real vtable/itable index
// default_vtable_indices stores the vtable value relative to this inheritor
if (default_index >= 0 ) {
is_default = true;
def_vtable_indices = klass->default_vtable_indices();
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.");
// 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);
}
// Static and <init> methods are never in // Static and <init> methods are never in
if (target_method()->is_static() || target_method()->name() == vmSymbols::object_initializer_name()) { if (target_method()->is_static() || target_method()->name() == vmSymbols::object_initializer_name()) {
@ -284,6 +332,8 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle tar
// An interface never allocates new vtable slots, only inherits old ones. // An interface never allocates new vtable slots, only inherits old ones.
// This method will either be assigned its own itable index later, // This method will either be assigned its own itable index later,
// or be assigned an inherited vtable index in the loop below. // or be assigned an inherited vtable index in the loop below.
// default methods store their vtable indices in the inheritors default_vtable_indices
assert (default_index == -1, "interfaces don't store resolved default methods");
target_method()->set_vtable_index(Method::pending_itable_index); target_method()->set_vtable_index(Method::pending_itable_index);
} }
@ -307,8 +357,15 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle tar
Symbol* name = target_method()->name(); Symbol* name = target_method()->name();
Symbol* signature = target_method()->signature(); Symbol* signature = target_method()->signature();
Handle target_loader(THREAD, _klass()->class_loader());
Symbol* target_classname = _klass->name(); KlassHandle target_klass(THREAD, target_method()->method_holder());
if (target_klass == NULL) {
target_klass = _klass;
}
Handle target_loader(THREAD, target_klass->class_loader());
Symbol* target_classname = target_klass->name();
for(int i = 0; i < super_vtable_len; i++) { for(int i = 0; i < super_vtable_len; i++) {
Method* super_method = method_at(i); Method* super_method = method_at(i);
// Check if method name matches // Check if method name matches
@ -317,10 +374,14 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle tar
// get super_klass for method_holder for the found method // get super_klass for method_holder for the found method
InstanceKlass* super_klass = super_method->method_holder(); InstanceKlass* super_klass = super_method->method_holder();
if ((super_klass->is_override(super_method, target_loader, target_classname, THREAD)) || if (is_default
((klass->major_version() >= VTABLE_TRANSITIVE_OVERRIDE_VERSION) || ((super_klass->is_override(super_method, target_loader, target_classname, THREAD))
&& ((super_klass = find_transitive_override(super_klass, target_method, i, target_loader, || ((klass->major_version() >= VTABLE_TRANSITIVE_OVERRIDE_VERSION)
target_classname, THREAD)) != (InstanceKlass*)NULL))) { && ((super_klass = find_transitive_override(super_klass,
target_method, i, target_loader,
target_classname, THREAD))
!= (InstanceKlass*)NULL))))
{
// overriding, so no new entry // overriding, so no new entry
allocate_new = false; allocate_new = false;
@ -347,7 +408,7 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle tar
"%s used in the signature"; "%s used in the signature";
char* sig = target_method()->name_and_sig_as_C_string(); char* sig = target_method()->name_and_sig_as_C_string();
const char* loader1 = SystemDictionary::loader_name(target_loader()); const char* loader1 = SystemDictionary::loader_name(target_loader());
char* current = _klass->name()->as_C_string(); char* current = target_klass->name()->as_C_string();
const char* loader2 = SystemDictionary::loader_name(super_loader()); const char* loader2 = SystemDictionary::loader_name(super_loader());
char* failed_type_name = failed_type_symbol->as_C_string(); char* failed_type_name = failed_type_symbol->as_C_string();
size_t buflen = strlen(msg) + strlen(sig) + strlen(loader1) + size_t buflen = strlen(msg) + strlen(sig) + strlen(loader1) +
@ -360,16 +421,39 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle tar
} }
} }
put_method_at(target_method(), i); put_method_at(target_method(), i);
target_method()->set_vtable_index(i); if (!is_default) {
target_method()->set_vtable_index(i);
} else {
if (def_vtable_indices != NULL) {
def_vtable_indices->at_put(default_index, i);
}
assert(super_method->is_default_method() || super_method->is_overpass()
|| super_method->is_abstract(), "default override error");
}
#ifndef PRODUCT #ifndef PRODUCT
if (PrintVtables && Verbose) { if (PrintVtables && Verbose) {
ResourceMark rm(THREAD);
char* sig = target_method()->name_and_sig_as_C_string();
tty->print("overriding with %s::%s index %d, original flags: ", tty->print("overriding with %s::%s index %d, original flags: ",
_klass->internal_name(), (target_method() != NULL) ? target_klass->internal_name(), sig, i);
target_method()->name()->as_C_string() : "<NULL>", i);
super_method->access_flags().print_on(tty); super_method->access_flags().print_on(tty);
if (super_method->is_default_method()) {
tty->print("default");
}
if (super_method->is_overpass()) {
tty->print("overpass");
}
tty->print("overriders flags: "); tty->print("overriders flags: ");
target_method->access_flags().print_on(tty); target_method->access_flags().print_on(tty);
if (target_method->is_default_method()) {
tty->print("default");
}
if (target_method->is_overpass()) {
tty->print("overpass");
}
tty->cr(); tty->cr();
} }
#endif /*PRODUCT*/ #endif /*PRODUCT*/
@ -378,12 +462,25 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle tar
// but not override another. Once we override one, not need new // but not override another. Once we override one, not need new
#ifndef PRODUCT #ifndef PRODUCT
if (PrintVtables && Verbose) { if (PrintVtables && Verbose) {
ResourceMark rm(THREAD);
char* sig = target_method()->name_and_sig_as_C_string();
tty->print("NOT overriding with %s::%s index %d, original flags: ", tty->print("NOT overriding with %s::%s index %d, original flags: ",
_klass->internal_name(), (target_method() != NULL) ? target_klass->internal_name(), sig,i);
target_method()->name()->as_C_string() : "<NULL>", i);
super_method->access_flags().print_on(tty); super_method->access_flags().print_on(tty);
if (super_method->is_default_method()) {
tty->print("default");
}
if (super_method->is_overpass()) {
tty->print("overpass");
}
tty->print("overriders flags: "); tty->print("overriders flags: ");
target_method->access_flags().print_on(tty); target_method->access_flags().print_on(tty);
if (target_method->is_default_method()) {
tty->print("default");
}
if (target_method->is_overpass()) {
tty->print("overpass");
}
tty->cr(); tty->cr();
} }
#endif /*PRODUCT*/ #endif /*PRODUCT*/
@ -438,6 +535,14 @@ bool klassVtable::needs_new_vtable_entry(methodHandle target_method,
return false; return false;
} }
// 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() ) {
return false;
}
// we need a new entry if there is no superclass // we need a new entry if there is no superclass
if (super == NULL) { if (super == NULL) {
return true; return true;
@ -446,7 +551,7 @@ bool klassVtable::needs_new_vtable_entry(methodHandle target_method,
// private methods in classes always have a new entry in the vtable // private methods in classes always have a new entry in the vtable
// specification interpretation since classic has // specification interpretation since classic has
// private methods not overriding // private methods not overriding
// JDK8 adds private methods in interfaces which require invokespecial // JDK8 adds private methods in interfaces which require invokespecial
if (target_method()->is_private()) { if (target_method()->is_private()) {
return true; return true;
} }
@ -526,35 +631,40 @@ bool klassVtable::is_miranda_entry_at(int i) {
if (mhk->is_interface()) { if (mhk->is_interface()) {
assert(m->is_public(), "should be public"); assert(m->is_public(), "should be public");
assert(ik()->implements_interface(method_holder) , "this class should implement the interface"); assert(ik()->implements_interface(method_holder) , "this class should implement the interface");
assert(is_miranda(m, ik()->methods(), ik()->super()), "should be a miranda_method"); assert(is_miranda(m, ik()->methods(), ik()->default_methods(), ik()->super()), "should be a miranda_method");
return true; return true;
} }
return false; return false;
} }
// check if a method is a miranda method, given a class's methods table and its super // check if a method is a miranda method, given a class's methods table,
// "miranda" means not static, not defined by this class, and not defined // its default_method table and its super
// in super unless it is private and therefore inaccessible to this class. // "miranda" means not static, not defined by this class.
// private methods in interfaces do not belong in the miranda list.
// the caller must make sure that the method belongs to an interface implemented by the class // the caller must make sure that the method belongs to an interface implemented by the class
// Miranda methods only include public interface instance methods // Miranda methods only include public interface instance methods
// Not private methods, not static methods, not default = concrete abstract // Not private methods, not static methods, not default == concrete abstract
bool klassVtable::is_miranda(Method* m, Array<Method*>* class_methods, Klass* super) { bool klassVtable::is_miranda(Method* m, Array<Method*>* class_methods,
if (m->is_static()) { Array<Method*>* default_methods, Klass* super) {
if (m->is_static() || m->is_private()) {
return false; return false;
} }
Symbol* name = m->name(); Symbol* name = m->name();
Symbol* signature = m->signature(); Symbol* signature = m->signature();
if (InstanceKlass::find_method(class_methods, name, signature) == NULL) { if (InstanceKlass::find_method(class_methods, name, signature) == NULL) {
// did not find it in the method table of the current class // did not find it in the method table of the current class
if (super == NULL) { if ((default_methods == NULL) ||
// super doesn't exist InstanceKlass::find_method(default_methods, name, signature) == NULL) {
return true; if (super == NULL) {
} // super doesn't exist
return true;
}
Method* mo = InstanceKlass::cast(super)->lookup_method(name, signature); Method* mo = InstanceKlass::cast(super)->lookup_method(name, signature);
if (mo == NULL || mo->access_flags().is_private() ) { if (mo == NULL || mo->access_flags().is_private() ) {
// super class hierarchy does not implement it or protection is different // super class hierarchy does not implement it or protection is different
return true; return true;
}
} }
} }
@ -562,7 +672,7 @@ bool klassVtable::is_miranda(Method* m, Array<Method*>* class_methods, Klass* su
} }
// Scans current_interface_methods for miranda methods that do not // Scans current_interface_methods for miranda methods that do not
// already appear in new_mirandas and are also not defined-and-non-private // already appear in new_mirandas, or default methods, and are also not defined-and-non-private
// in super (superclass). These mirandas are added to all_mirandas if it is // in super (superclass). These mirandas are added to all_mirandas if it is
// not null; in addition, those that are not duplicates of miranda methods // not null; in addition, those that are not duplicates of miranda methods
// inherited by super from its interfaces are added to new_mirandas. // inherited by super from its interfaces are added to new_mirandas.
@ -572,7 +682,8 @@ bool klassVtable::is_miranda(Method* m, Array<Method*>* class_methods, Klass* su
void klassVtable::add_new_mirandas_to_lists( void klassVtable::add_new_mirandas_to_lists(
GrowableArray<Method*>* new_mirandas, GrowableArray<Method*>* all_mirandas, GrowableArray<Method*>* new_mirandas, GrowableArray<Method*>* all_mirandas,
Array<Method*>* current_interface_methods, Array<Method*>* class_methods, Array<Method*>* current_interface_methods, Array<Method*>* class_methods,
Klass* super) { Array<Method*>* default_methods, Klass* super) {
// iterate thru the current interface's method to see if it a miranda // iterate thru the current interface's method to see if it a miranda
int num_methods = current_interface_methods->length(); int num_methods = current_interface_methods->length();
for (int i = 0; i < num_methods; i++) { for (int i = 0; i < num_methods; i++) {
@ -590,7 +701,7 @@ void klassVtable::add_new_mirandas_to_lists(
} }
if (!is_duplicate) { // we don't want duplicate miranda entries in the vtable if (!is_duplicate) { // we don't want duplicate miranda entries in the vtable
if (is_miranda(im, class_methods, super)) { // is it a miranda at all? if (is_miranda(im, class_methods, default_methods, super)) { // is it a miranda at all?
InstanceKlass *sk = InstanceKlass::cast(super); InstanceKlass *sk = InstanceKlass::cast(super);
// check if it is a duplicate of a super's miranda // check if it is a duplicate of a super's miranda
if (sk->lookup_method_in_all_interfaces(im->name(), im->signature()) == NULL) { if (sk->lookup_method_in_all_interfaces(im->name(), im->signature()) == NULL) {
@ -607,6 +718,7 @@ void klassVtable::add_new_mirandas_to_lists(
void klassVtable::get_mirandas(GrowableArray<Method*>* new_mirandas, void klassVtable::get_mirandas(GrowableArray<Method*>* new_mirandas,
GrowableArray<Method*>* all_mirandas, GrowableArray<Method*>* all_mirandas,
Klass* super, Array<Method*>* class_methods, Klass* super, Array<Method*>* class_methods,
Array<Method*>* default_methods,
Array<Klass*>* local_interfaces) { Array<Klass*>* local_interfaces) {
assert((new_mirandas->length() == 0) , "current mirandas must be 0"); assert((new_mirandas->length() == 0) , "current mirandas must be 0");
@ -615,14 +727,16 @@ void klassVtable::get_mirandas(GrowableArray<Method*>* new_mirandas,
for (int i = 0; i < num_local_ifs; i++) { for (int i = 0; i < num_local_ifs; i++) {
InstanceKlass *ik = InstanceKlass::cast(local_interfaces->at(i)); InstanceKlass *ik = InstanceKlass::cast(local_interfaces->at(i));
add_new_mirandas_to_lists(new_mirandas, all_mirandas, add_new_mirandas_to_lists(new_mirandas, all_mirandas,
ik->methods(), class_methods, super); ik->methods(), class_methods,
default_methods, super);
// iterate thru each local's super interfaces // iterate thru each local's super interfaces
Array<Klass*>* super_ifs = ik->transitive_interfaces(); Array<Klass*>* super_ifs = ik->transitive_interfaces();
int num_super_ifs = super_ifs->length(); int num_super_ifs = super_ifs->length();
for (int j = 0; j < num_super_ifs; j++) { for (int j = 0; j < num_super_ifs; j++) {
InstanceKlass *sik = InstanceKlass::cast(super_ifs->at(j)); InstanceKlass *sik = InstanceKlass::cast(super_ifs->at(j));
add_new_mirandas_to_lists(new_mirandas, all_mirandas, add_new_mirandas_to_lists(new_mirandas, all_mirandas,
sik->methods(), class_methods, super); sik->methods(), class_methods,
default_methods, super);
} }
} }
} }
@ -633,8 +747,22 @@ void klassVtable::get_mirandas(GrowableArray<Method*>* new_mirandas,
int klassVtable::fill_in_mirandas(int initialized) { int klassVtable::fill_in_mirandas(int initialized) {
GrowableArray<Method*> mirandas(20); GrowableArray<Method*> mirandas(20);
get_mirandas(&mirandas, NULL, ik()->super(), ik()->methods(), get_mirandas(&mirandas, NULL, ik()->super(), ik()->methods(),
ik()->local_interfaces()); ik()->default_methods(), ik()->local_interfaces());
for (int i = 0; i < mirandas.length(); i++) { for (int i = 0; i < mirandas.length(); i++) {
if (PrintVtables && Verbose) {
Method* meth = mirandas.at(i);
ResourceMark rm(Thread::current());
if (meth != NULL) {
char* sig = meth->name_and_sig_as_C_string();
tty->print("fill in mirandas with %s index %d, flags: ",
sig, initialized);
meth->access_flags().print_on(tty);
if (meth->is_default_method()) {
tty->print("default");
}
tty->cr();
}
}
put_method_at(mirandas.at(i), initialized); put_method_at(mirandas.at(i), initialized);
++initialized; ++initialized;
} }
@ -648,6 +776,26 @@ void klassVtable::copy_vtable_to(vtableEntry* start) {
} }
#if INCLUDE_JVMTI #if INCLUDE_JVMTI
bool klassVtable::adjust_default_method(int vtable_index, Method* old_method, Method* new_method) {
// If old_method is default, find this vtable index in default_vtable_indices
// and replace that method in the _default_methods list
bool updated = false;
Array<Method*>* default_methods = ik()->default_methods();
if (default_methods != NULL) {
int len = default_methods->length();
for (int idx = 0; idx < len; idx++) {
if (vtable_index == ik()->default_vtable_indices()->at(idx)) {
if (default_methods->at(idx) == old_method) {
default_methods->at_put(idx, new_method);
updated = true;
}
break;
}
}
}
return updated;
}
void klassVtable::adjust_method_entries(Method** old_methods, Method** new_methods, void klassVtable::adjust_method_entries(Method** old_methods, Method** new_methods,
int methods_length, bool * trace_name_printed) { int methods_length, bool * trace_name_printed) {
// search the vtable for uses of either obsolete or EMCP methods // search the vtable for uses of either obsolete or EMCP methods
@ -663,18 +811,26 @@ void klassVtable::adjust_method_entries(Method** old_methods, Method** new_metho
for (int index = 0; index < length(); index++) { for (int index = 0; index < length(); index++) {
if (unchecked_method_at(index) == old_method) { if (unchecked_method_at(index) == old_method) {
put_method_at(new_method, index); put_method_at(new_method, index);
// For default methods, need to update the _default_methods array
// which can only have one method entry for a given signature
bool updated_default = false;
if (old_method->is_default_method()) {
updated_default = adjust_default_method(index, old_method, new_method);
}
if (RC_TRACE_IN_RANGE(0x00100000, 0x00400000)) { if (RC_TRACE_IN_RANGE(0x00100000, 0x00400000)) {
if (!(*trace_name_printed)) { if (!(*trace_name_printed)) {
// RC_TRACE_MESG macro has an embedded ResourceMark // RC_TRACE_MESG macro has an embedded ResourceMark
RC_TRACE_MESG(("adjust: name=%s", RC_TRACE_MESG(("adjust: klassname=%s for methods from name=%s",
klass()->external_name(),
old_method->method_holder()->external_name())); old_method->method_holder()->external_name()));
*trace_name_printed = true; *trace_name_printed = true;
} }
// RC_TRACE macro has an embedded ResourceMark // RC_TRACE macro has an embedded ResourceMark
RC_TRACE(0x00100000, ("vtable method update: %s(%s)", RC_TRACE(0x00100000, ("vtable method update: %s(%s), updated default = %s",
new_method->name()->as_C_string(), new_method->name()->as_C_string(),
new_method->signature()->as_C_string())); new_method->signature()->as_C_string(),
updated_default ? "true" : "false"));
} }
// cannot 'break' here; see for-loop comment above. // cannot 'break' here; see for-loop comment above.
} }
@ -701,6 +857,12 @@ void klassVtable::dump_vtable() {
if (m != NULL) { if (m != NULL) {
tty->print(" (%5d) ", i); tty->print(" (%5d) ", i);
m->access_flags().print_on(tty); m->access_flags().print_on(tty);
if (m->is_default_method()) {
tty->print("default");
}
if (m->is_overpass()) {
tty->print("overpass");
}
tty->print(" -- "); tty->print(" -- ");
m->print_name(tty); m->print_name(tty);
tty->cr(); tty->cr();
@ -757,9 +919,9 @@ static int initialize_count = 0;
// Initialization // Initialization
void klassItable::initialize_itable(bool checkconstraints, TRAPS) { void klassItable::initialize_itable(bool checkconstraints, TRAPS) {
if (_klass->is_interface()) { if (_klass->is_interface()) {
// This needs to go after vtable indexes are assigned but // This needs to go after vtable indices are assigned but
// before implementors need to know the number of itable indexes. // before implementors need to know the number of itable indices.
assign_itable_indexes_for_interface(_klass()); assign_itable_indices_for_interface(_klass());
} }
// Cannot be setup doing bootstrapping, interfaces don't have // Cannot be setup doing bootstrapping, interfaces don't have
@ -803,7 +965,7 @@ inline bool interface_method_needs_itable_index(Method* m) {
return true; return true;
} }
int klassItable::assign_itable_indexes_for_interface(Klass* klass) { int klassItable::assign_itable_indices_for_interface(Klass* klass) {
// an interface does not have an itable, but its methods need to be numbered // an interface does not have an itable, but its methods need to be numbered
if (TraceItables) tty->print_cr("%3d: Initializing itable for interface %s", ++initialize_count, if (TraceItables) tty->print_cr("%3d: Initializing itable for interface %s", ++initialize_count,
klass->name()->as_C_string()); klass->name()->as_C_string());
@ -846,7 +1008,7 @@ int klassItable::method_count_for_interface(Klass* interf) {
} }
nof_methods -= 1; nof_methods -= 1;
} }
// no methods have itable indexes // no methods have itable indices
return 0; return 0;
} }
@ -907,6 +1069,21 @@ void klassItable::initialize_itable_for_interface(int method_table_offset, Klass
int ime_num = m->itable_index(); int ime_num = m->itable_index();
assert(ime_num < ime_count, "oob"); assert(ime_num < ime_count, "oob");
itableOffsetEntry::method_entry(_klass(), method_table_offset)[ime_num].initialize(target()); itableOffsetEntry::method_entry(_klass(), method_table_offset)[ime_num].initialize(target());
if (TraceItables && Verbose) {
ResourceMark rm(THREAD);
if (target() != NULL) {
char* sig = target()->name_and_sig_as_C_string();
tty->print("interface: %s, ime_num: %d, target: %s, method_holder: %s ",
interf_h()->internal_name(), ime_num, sig,
target()->method_holder()->internal_name());
tty->print("target_method flags: ");
target()->access_flags().print_on(tty);
if (target()->is_default_method()) {
tty->print("default");
}
tty->cr();
}
}
} }
} }
} }
@ -980,6 +1157,9 @@ void klassItable::dump_itable() {
if (m != NULL) { if (m != NULL) {
tty->print(" (%5d) ", i); tty->print(" (%5d) ", i);
m->access_flags().print_on(tty); m->access_flags().print_on(tty);
if (m->is_default_method()) {
tty->print("default");
}
tty->print(" -- "); tty->print(" -- ");
m->print_name(tty); m->print_name(tty);
tty->cr(); tty->cr();
@ -1116,7 +1296,7 @@ Method* klassItable::method_for_itable_index(Klass* intf, int itable_index) {
Array<Method*>* methods = InstanceKlass::cast(intf)->methods(); Array<Method*>* methods = InstanceKlass::cast(intf)->methods();
if (itable_index < 0 || itable_index >= method_count_for_interface(intf)) if (itable_index < 0 || itable_index >= method_count_for_interface(intf))
return NULL; // help caller defend against bad indexes return NULL; // help caller defend against bad indices
int index = itable_index; int index = itable_index;
Method* m = methods->at(index); Method* m = methods->at(index);

View file

@ -97,6 +97,7 @@ class klassVtable : public ResourceObj {
// trace_name_printed is set to true if the current call has // trace_name_printed is set to true if the current call has
// printed the klass name so that other routines in the adjust_* // printed the klass name so that other routines in the adjust_*
// group don't print the klass name. // group don't print the klass name.
bool adjust_default_method(int vtable_index, Method* old_method, Method* new_method);
void adjust_method_entries(Method** old_methods, Method** new_methods, void adjust_method_entries(Method** old_methods, Method** new_methods,
int methods_length, bool * trace_name_printed); int methods_length, bool * trace_name_printed);
bool check_no_old_or_obsolete_entries(); bool check_no_old_or_obsolete_entries();
@ -118,24 +119,28 @@ class klassVtable : public ResourceObj {
void put_method_at(Method* m, int index); void put_method_at(Method* m, int index);
static bool needs_new_vtable_entry(methodHandle m, Klass* super, Handle classloader, Symbol* classname, AccessFlags access_flags, TRAPS); static bool needs_new_vtable_entry(methodHandle m, Klass* super, Handle classloader, Symbol* classname, AccessFlags access_flags, TRAPS);
bool update_inherited_vtable(InstanceKlass* klass, methodHandle target_method, int super_vtable_len, bool checkconstraints, TRAPS); bool update_inherited_vtable(InstanceKlass* klass, methodHandle target_method, int super_vtable_len, int default_index, bool checkconstraints, TRAPS);
InstanceKlass* find_transitive_override(InstanceKlass* initialsuper, methodHandle target_method, int vtable_index, InstanceKlass* find_transitive_override(InstanceKlass* initialsuper, methodHandle target_method, int vtable_index,
Handle target_loader, Symbol* target_classname, Thread* THREAD); Handle target_loader, Symbol* target_classname, Thread* THREAD);
// support for miranda methods // support for miranda methods
bool is_miranda_entry_at(int i); bool is_miranda_entry_at(int i);
int fill_in_mirandas(int initialized); int fill_in_mirandas(int initialized);
static bool is_miranda(Method* m, Array<Method*>* class_methods, Klass* super); static bool is_miranda(Method* m, Array<Method*>* class_methods,
Array<Method*>* default_methods, Klass* super);
static void add_new_mirandas_to_lists( static void add_new_mirandas_to_lists(
GrowableArray<Method*>* new_mirandas, GrowableArray<Method*>* new_mirandas,
GrowableArray<Method*>* all_mirandas, GrowableArray<Method*>* all_mirandas,
Array<Method*>* current_interface_methods, Array<Method*>* class_methods, Array<Method*>* current_interface_methods,
Array<Method*>* class_methods,
Array<Method*>* default_methods,
Klass* super); Klass* super);
static void get_mirandas( static void get_mirandas(
GrowableArray<Method*>* new_mirandas, GrowableArray<Method*>* new_mirandas,
GrowableArray<Method*>* all_mirandas, Klass* super, GrowableArray<Method*>* all_mirandas, Klass* super,
Array<Method*>* class_methods, Array<Klass*>* local_interfaces); Array<Method*>* class_methods,
Array<Method*>* default_methods,
Array<Klass*>* local_interfaces);
void verify_against(outputStream* st, klassVtable* vt, int index); void verify_against(outputStream* st, klassVtable* vt, int index);
inline InstanceKlass* ik() const; inline InstanceKlass* ik() const;
}; };
@ -290,7 +295,7 @@ class klassItable : public ResourceObj {
#endif // INCLUDE_JVMTI #endif // INCLUDE_JVMTI
// Setup of itable // Setup of itable
static int assign_itable_indexes_for_interface(Klass* klass); static int assign_itable_indices_for_interface(Klass* klass);
static int method_count_for_interface(Klass* klass); static int method_count_for_interface(Klass* klass);
static int compute_itable_size(Array<Klass*>* transitive_interfaces); static int compute_itable_size(Array<Klass*>* transitive_interfaces);
static void setup_itable_offset_table(instanceKlassHandle klass); static void setup_itable_offset_table(instanceKlassHandle klass);

View file

@ -511,9 +511,9 @@ bool Method::compute_has_loops_flag() {
bool Method::is_final_method(AccessFlags class_access_flags) const { bool Method::is_final_method(AccessFlags class_access_flags) const {
// or "does_not_require_vtable_entry" // or "does_not_require_vtable_entry"
// overpass can occur, is not final (reuses vtable entry) // default method or overpass can occur, is not final (reuses vtable entry)
// private methods get vtable entries for backward class compatibility. // private methods get vtable entries for backward class compatibility.
if (is_overpass()) return false; if (is_overpass() || is_default_method()) return false;
return is_final() || class_access_flags.is_final(); return is_final() || class_access_flags.is_final();
} }
@ -521,11 +521,24 @@ bool Method::is_final_method() const {
return is_final_method(method_holder()->access_flags()); return is_final_method(method_holder()->access_flags());
} }
bool Method::is_default_method() const {
if (method_holder() != NULL &&
method_holder()->is_interface() &&
!is_abstract()) {
return true;
} else {
return false;
}
}
bool Method::can_be_statically_bound(AccessFlags class_access_flags) const { bool Method::can_be_statically_bound(AccessFlags class_access_flags) const {
if (is_final_method(class_access_flags)) return true; if (is_final_method(class_access_flags)) return true;
#ifdef ASSERT #ifdef ASSERT
ResourceMark rm;
bool is_nonv = (vtable_index() == nonvirtual_vtable_index); bool is_nonv = (vtable_index() == nonvirtual_vtable_index);
if (class_access_flags.is_interface()) assert(is_nonv == is_static(), err_msg("is_nonv=%s", is_nonv)); if (class_access_flags.is_interface()) {
assert(is_nonv == is_static(), err_msg("is_nonv=%s", name_and_sig_as_C_string()));
}
#endif #endif
assert(valid_vtable_index() || valid_itable_index(), "method must be linked before we ask this question"); assert(valid_vtable_index() || valid_itable_index(), "method must be linked before we ask this question");
return vtable_index() == nonvirtual_vtable_index; return vtable_index() == nonvirtual_vtable_index;
@ -1371,7 +1384,8 @@ static int method_comparator(Method* a, Method* b) {
} }
// This is only done during class loading, so it is OK to assume method_idnum matches the methods() array // This is only done during class loading, so it is OK to assume method_idnum matches the methods() array
void Method::sort_methods(Array<Method*>* methods, bool idempotent) { // default_methods also uses this without the ordering for fast find_method
void Method::sort_methods(Array<Method*>* methods, bool idempotent, bool set_idnums) {
int length = methods->length(); int length = methods->length();
if (length > 1) { if (length > 1) {
{ {
@ -1379,14 +1393,15 @@ void Method::sort_methods(Array<Method*>* methods, bool idempotent) {
QuickSort::sort<Method*>(methods->data(), length, method_comparator, idempotent); QuickSort::sort<Method*>(methods->data(), length, method_comparator, idempotent);
} }
// Reset method ordering // Reset method ordering
for (int i = 0; i < length; i++) { if (set_idnums) {
Method* m = methods->at(i); for (int i = 0; i < length; i++) {
m->set_method_idnum(i); Method* m = methods->at(i);
m->set_method_idnum(i);
}
} }
} }
} }
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
// Non-product code unless JVM/TI needs it // Non-product code unless JVM/TI needs it

View file

@ -567,6 +567,7 @@ class Method : public Metadata {
// checks method and its method holder // checks method and its method holder
bool is_final_method() const; bool is_final_method() const;
bool is_final_method(AccessFlags class_access_flags) const; bool is_final_method(AccessFlags class_access_flags) const;
bool is_default_method() const;
// true if method needs no dynamic dispatch (final and/or no vtable entry) // true if method needs no dynamic dispatch (final and/or no vtable entry)
bool can_be_statically_bound() const; bool can_be_statically_bound() const;
@ -846,7 +847,7 @@ class Method : public Metadata {
#endif #endif
// Helper routine used for method sorting // Helper routine used for method sorting
static void sort_methods(Array<Method*>* methods, bool idempotent = false); static void sort_methods(Array<Method*>* methods, bool idempotent = false, bool set_idnums = true);
// Deallocation function for redefine classes or if an error occurs // Deallocation function for redefine classes or if an error occurs
void deallocate_contents(ClassLoaderData* loader_data); void deallocate_contents(ClassLoaderData* loader_data);

View file

@ -1591,10 +1591,8 @@ static jmethodID get_method_id(JNIEnv *env, jclass clazz, const char *name_str,
} }
} else { } else {
m = klass->lookup_method(name, signature); m = klass->lookup_method(name, signature);
// Look up interfaces if (m == NULL && klass->oop_is_instance()) {
if (m == NULL && klass->oop_is_instance()) { m = InstanceKlass::cast(klass())->lookup_method_in_ordered_interfaces(name, signature);
m = InstanceKlass::cast(klass())->lookup_method_in_all_interfaces(name,
signature);
} }
} }
if (m == NULL || (m->is_static() != is_static)) { if (m == NULL || (m->is_static() != is_static)) {

View file

@ -2755,13 +2755,26 @@ void VM_RedefineClasses::AdjustCpoolCacheAndVtable::do_klass(Klass* k) {
// InstanceKlass around to hold obsolete methods so we don't have // InstanceKlass around to hold obsolete methods so we don't have
// any other InstanceKlass embedded vtables to update. The vtable // any other InstanceKlass embedded vtables to update. The vtable
// holds the Method*s for virtual (but not final) methods. // holds the Method*s for virtual (but not final) methods.
if (ik->vtable_length() > 0 && ik->is_subtype_of(_the_class_oop)) { // Default methods, or concrete methods in interfaces are stored
// in the vtable, so if an interface changes we need to check
// adjust_method_entries() for every InstanceKlass, which will also
// adjust the default method vtable indices.
// We also need to adjust any default method entries that are
// not yet in the vtable, because the vtable setup is in progress.
// This must be done after we adjust the default_methods and
// default_vtable_indices for methods already in the vtable.
if (ik->vtable_length() > 0 && (_the_class_oop->is_interface()
|| ik->is_subtype_of(_the_class_oop))) {
// ik->vtable() creates a wrapper object; rm cleans it up // ik->vtable() creates a wrapper object; rm cleans it up
ResourceMark rm(_thread); ResourceMark rm(_thread);
ik->vtable()->adjust_method_entries(_matching_old_methods, ik->vtable()->adjust_method_entries(_matching_old_methods,
_matching_new_methods, _matching_new_methods,
_matching_methods_length, _matching_methods_length,
&trace_name_printed); &trace_name_printed);
ik->adjust_default_methods(_matching_old_methods,
_matching_new_methods,
_matching_methods_length,
&trace_name_printed);
} }
// If the current class has an itable and we are either redefining an // If the current class has an itable and we are either redefining an

View file

@ -187,12 +187,34 @@ oop MethodHandles::init_method_MemberName(Handle mname, CallInfo& info) {
receiver_limit = m->method_holder(); receiver_limit = m->method_holder();
assert(receiver_limit->verify_itable_index(vmindex), ""); assert(receiver_limit->verify_itable_index(vmindex), "");
flags |= IS_METHOD | (JVM_REF_invokeInterface << REFERENCE_KIND_SHIFT); flags |= IS_METHOD | (JVM_REF_invokeInterface << REFERENCE_KIND_SHIFT);
if (TraceInvokeDynamic) {
ResourceMark rm;
tty->print_cr("memberName: invokeinterface method_holder::method: %s, receiver: %s, itableindex: %d, access_flags:",
Method::name_and_sig_as_C_string(receiver_limit(), m->name(), m->signature()),
receiver_limit()->internal_name(), vmindex);
m->access_flags().print_on(tty);
if (!m->is_abstract()) {
tty->print("default");
}
tty->cr();
}
break; break;
case CallInfo::vtable_call: case CallInfo::vtable_call:
vmindex = info.vtable_index(); vmindex = info.vtable_index();
flags |= IS_METHOD | (JVM_REF_invokeVirtual << REFERENCE_KIND_SHIFT); flags |= IS_METHOD | (JVM_REF_invokeVirtual << REFERENCE_KIND_SHIFT);
assert(receiver_limit->is_subtype_of(m->method_holder()), "virtual call must be type-safe"); assert(receiver_limit->is_subtype_of(m->method_holder()), "virtual call must be type-safe");
if (TraceInvokeDynamic) {
ResourceMark rm;
tty->print_cr("memberName: invokevirtual method_holder::method: %s, receiver: %s, vtableindex: %d, access_flags:",
Method::name_and_sig_as_C_string(receiver_limit(), m->name(), m->signature()),
receiver_limit()->internal_name(), vmindex);
m->access_flags().print_on(tty);
if (m->is_default_method()) {
tty->print("default");
}
tty->cr();
}
break; break;
case CallInfo::direct_call: case CallInfo::direct_call:

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -27,8 +27,11 @@
#include "memory/universe.inline.hpp" #include "memory/universe.inline.hpp"
#include "runtime/reflectionUtils.hpp" #include "runtime/reflectionUtils.hpp"
KlassStream::KlassStream(instanceKlassHandle klass, bool local_only, bool classes_only) { KlassStream::KlassStream(instanceKlassHandle klass, bool local_only,
_klass = klass; bool classes_only, bool walk_defaults) {
_klass = _base_klass = klass;
_base_class_search_defaults = false;
_defaults_checked = false;
if (classes_only) { if (classes_only) {
_interfaces = Universe::the_empty_klass_array(); _interfaces = Universe::the_empty_klass_array();
} else { } else {
@ -37,6 +40,7 @@ KlassStream::KlassStream(instanceKlassHandle klass, bool local_only, bool classe
_interface_index = _interfaces->length(); _interface_index = _interfaces->length();
_local_only = local_only; _local_only = local_only;
_classes_only = classes_only; _classes_only = classes_only;
_walk_defaults = walk_defaults;
} }
bool KlassStream::eos() { bool KlassStream::eos() {
@ -45,7 +49,13 @@ bool KlassStream::eos() {
if (!_klass->is_interface() && _klass->super() != NULL) { if (!_klass->is_interface() && _klass->super() != NULL) {
// go up superclass chain (not for interfaces) // go up superclass chain (not for interfaces)
_klass = _klass->super(); _klass = _klass->super();
// Next for method walks, walk default methods
} else if (_walk_defaults && (_defaults_checked == false) && (_base_klass->default_methods() != NULL)) {
_base_class_search_defaults = true;
_klass = _base_klass;
_defaults_checked = true;
} else { } else {
// Next walk transitive interfaces
if (_interface_index > 0) { if (_interface_index > 0) {
_klass = _interfaces->at(--_interface_index); _klass = _interfaces->at(--_interface_index);
} else { } else {

View file

@ -38,7 +38,7 @@
// and (super)interfaces. Streaming is done in reverse order (subclasses first, // and (super)interfaces. Streaming is done in reverse order (subclasses first,
// interfaces last). // interfaces last).
// //
// for (KlassStream st(k, false, false); !st.eos(); st.next()) { // for (KlassStream st(k, false, false, false); !st.eos(); st.next()) {
// Klass* k = st.klass(); // Klass* k = st.klass();
// ... // ...
// } // }
@ -46,17 +46,21 @@
class KlassStream VALUE_OBJ_CLASS_SPEC { class KlassStream VALUE_OBJ_CLASS_SPEC {
protected: protected:
instanceKlassHandle _klass; // current klass/interface iterated over instanceKlassHandle _klass; // current klass/interface iterated over
Array<Klass*>* _interfaces; // transitive interfaces for initial class instanceKlassHandle _base_klass; // initial klass/interface to iterate over
Array<Klass*>* _interfaces; // transitive interfaces for initial class
int _interface_index; // current interface being processed int _interface_index; // current interface being processed
bool _local_only; // process initial class/interface only bool _local_only; // process initial class/interface only
bool _classes_only; // process classes only (no interfaces) bool _classes_only; // process classes only (no interfaces)
bool _walk_defaults; // process default methods
bool _base_class_search_defaults; // time to process default methods
bool _defaults_checked; // already checked for default methods
int _index; int _index;
virtual int length() const = 0; virtual int length() = 0;
public: public:
// constructor // constructor
KlassStream(instanceKlassHandle klass, bool local_only, bool classes_only); KlassStream(instanceKlassHandle klass, bool local_only, bool classes_only, bool walk_defaults);
// testing // testing
bool eos(); bool eos();
@ -67,6 +71,8 @@ class KlassStream VALUE_OBJ_CLASS_SPEC {
// accessors // accessors
instanceKlassHandle klass() const { return _klass; } instanceKlassHandle klass() const { return _klass; }
int index() const { return _index; } int index() const { return _index; }
bool base_class_search_defaults() const { return _base_class_search_defaults; }
void base_class_search_defaults(bool b) { _base_class_search_defaults = b; }
}; };
@ -81,17 +87,24 @@ class KlassStream VALUE_OBJ_CLASS_SPEC {
class MethodStream : public KlassStream { class MethodStream : public KlassStream {
private: private:
int length() const { return methods()->length(); } int length() { return methods()->length(); }
Array<Method*>* methods() const { return _klass->methods(); } Array<Method*>* methods() {
if (base_class_search_defaults()) {
base_class_search_defaults(false);
return _klass->default_methods();
} else {
return _klass->methods();
}
}
public: public:
MethodStream(instanceKlassHandle klass, bool local_only, bool classes_only) MethodStream(instanceKlassHandle klass, bool local_only, bool classes_only)
: KlassStream(klass, local_only, classes_only) { : KlassStream(klass, local_only, classes_only, true) {
_index = length(); _index = length();
next(); next();
} }
void next() { _index--; } void next() { _index--; }
Method* method() const { return methods()->at(index()); } Method* method() { return methods()->at(index()); }
}; };
@ -107,13 +120,13 @@ class MethodStream : public KlassStream {
class FieldStream : public KlassStream { class FieldStream : public KlassStream {
private: private:
int length() const { return _klass->java_fields_count(); } int length() { return _klass->java_fields_count(); }
fieldDescriptor _fd_buf; fieldDescriptor _fd_buf;
public: public:
FieldStream(instanceKlassHandle klass, bool local_only, bool classes_only) FieldStream(instanceKlassHandle klass, bool local_only, bool classes_only)
: KlassStream(klass, local_only, classes_only) { : KlassStream(klass, local_only, classes_only, false) {
_index = length(); _index = length();
next(); next();
} }

View file

@ -289,6 +289,7 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
nonstatic_field(ConstantPoolCache, _constant_pool, ConstantPool*) \ nonstatic_field(ConstantPoolCache, _constant_pool, ConstantPool*) \
nonstatic_field(InstanceKlass, _array_klasses, Klass*) \ nonstatic_field(InstanceKlass, _array_klasses, Klass*) \
nonstatic_field(InstanceKlass, _methods, Array<Method*>*) \ nonstatic_field(InstanceKlass, _methods, Array<Method*>*) \
nonstatic_field(InstanceKlass, _default_methods, Array<Method*>*) \
nonstatic_field(InstanceKlass, _local_interfaces, Array<Klass*>*) \ nonstatic_field(InstanceKlass, _local_interfaces, Array<Klass*>*) \
nonstatic_field(InstanceKlass, _transitive_interfaces, Array<Klass*>*) \ nonstatic_field(InstanceKlass, _transitive_interfaces, Array<Klass*>*) \
nonstatic_field(InstanceKlass, _fields, Array<u2>*) \ nonstatic_field(InstanceKlass, _fields, Array<u2>*) \
@ -323,6 +324,7 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
nonstatic_field(nmethodBucket, _count, int) \ nonstatic_field(nmethodBucket, _count, int) \
nonstatic_field(nmethodBucket, _next, nmethodBucket*) \ nonstatic_field(nmethodBucket, _next, nmethodBucket*) \
nonstatic_field(InstanceKlass, _method_ordering, Array<int>*) \ nonstatic_field(InstanceKlass, _method_ordering, Array<int>*) \
nonstatic_field(InstanceKlass, _default_vtable_indices, Array<int>*) \
nonstatic_field(Klass, _super_check_offset, juint) \ nonstatic_field(Klass, _super_check_offset, juint) \
nonstatic_field(Klass, _secondary_super_cache, Klass*) \ nonstatic_field(Klass, _secondary_super_cache, Klass*) \
nonstatic_field(Klass, _secondary_supers, Array<Klass*>*) \ nonstatic_field(Klass, _secondary_supers, Array<Klass*>*) \