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

@ -345,7 +345,6 @@ class MethodFamily : public ResourceObj {
}
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;
public:
@ -404,20 +403,19 @@ class MethodFamily : public ResourceObj {
_exception_message = generate_no_defaults_message(CHECK);
_exception_name = vmSymbols::java_lang_AbstractMethodError();
} else if (qualified_methods.length() == 1) {
// leave abstract methods alone, they will be found via normal search path
Method* method = qualified_methods.at(0);
if (method->is_abstract()) {
_exception_message = generate_abstract_method_message(method, CHECK);
_exception_name = vmSymbols::java_lang_AbstractMethodError();
} else {
if (!method->is_abstract()) {
_selected_target = qualified_methods.at(0);
}
} else {
_exception_message = generate_conflicts_message(&qualified_methods,CHECK);
_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) {
@ -475,20 +473,6 @@ Symbol* MethodFamily::generate_no_defaults_message(TRAPS) const {
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 {
stringStream ss;
ss.print("Conflicting default methods:");
@ -595,6 +579,18 @@ class EmptyVtableSlot : public ResourceObj {
#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(
InstanceKlass* klass, GrowableArray<Method*>* mirandas, TRAPS) {
@ -604,8 +600,10 @@ static GrowableArray<EmptyVtableSlot*>* find_empty_vtable_slots(
// All miranda methods are obvious candidates
for (int i = 0; i < mirandas->length(); ++i) {
EmptyVtableSlot* slot = new EmptyVtableSlot(mirandas->at(i));
slots->append(slot);
Method* m = mirandas->at(i);
if (!already_in_vtable_slots(slots, m)) {
slots->append(new EmptyVtableSlot(m));
}
}
// 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.
Method* impl = klass->lookup_method(m->name(), m->signature());
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
// invokespecial to private interface methods doesn't use default method logic
// 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) {
_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);
static void generate_erased_defaults(
@ -721,6 +738,8 @@ static void generate_erased_defaults(
static void merge_in_new_methods(InstanceKlass* klass,
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
// after the classfile has been parsed if some ancestor has default methods.
@ -782,7 +801,7 @@ void DefaultMethods::generate_default_methods(
}
#endif // ndef PRODUCT
create_overpasses(empty_slots, klass, CHECK);
create_defaults_and_exceptions(empty_slots, klass, CHECK);
#ifndef PRODUCT
if (TraceDefaultMethods) {
@ -791,66 +810,6 @@ void DefaultMethods::generate_default_methods(
#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(
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
// an implementation and a generically-compatible, but different, signature.
// Bridges have actual bytecode implementation in classfiles.
// An "overpass", on the other hand, performs the same function as a bridge
// but does not occur in a classfile; the VM creates overpass itself,
// when it needs a path to get from a call site to an default method, and
// a bridge doesn't exist.
static void create_overpasses(
// Create default_methods list for the current class.
// With the VM only processing erased signatures, the VM only
// creates an overpass in a conflict case or a case with no candidates.
// This allows virtual methods to override the overpass, but ensures
// that a local method search will find the exception rather than an abstract
// or default method that is not a valid candidate.
static void create_defaults_and_exceptions(
GrowableArray<EmptyVtableSlot*>* slots,
InstanceKlass* klass, TRAPS) {
GrowableArray<Method*> overpasses;
GrowableArray<Method*> defaults;
BytecodeConstantPool bpool(klass->constants());
for (int i = 0; i < slots->length(); ++i) {
@ -943,7 +902,6 @@ static void create_overpasses(
if (slot->is_bound()) {
MethodFamily* method = slot->get_binding();
int max_stack = 0;
BytecodeBuffer buffer;
#ifndef PRODUCT
@ -953,26 +911,27 @@ static void create_overpasses(
tty->print_cr("");
if (method->has_target()) {
method->print_selected(tty, 1);
} else {
} else if (method->throws_exception()) {
method->print_exception(tty, 1);
}
}
#endif // ndef PRODUCT
if (method->has_target()) {
Method* selected = method->get_selected_target();
if (selected->method_holder()->is_interface()) {
max_stack = assemble_redirect(
&bpool, &buffer, slot->signature(), selected, CHECK);
defaults.push(selected);
}
} else if (method->throws_exception()) {
max_stack = assemble_method_error(&bpool, &buffer, method->get_exception_name(), method->get_exception_message(), CHECK);
}
if (max_stack != 0) {
int max_stack = assemble_method_error(&bpool, &buffer,
method->get_exception_name(), method->get_exception_message(), CHECK);
AccessFlags flags = accessFlags_from(
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(),
ConstMethod::OVERPASS, CHECK);
// We push to the methods list:
// overpass methods which are exception throwing methods
if (m != NULL) {
overpasses.push(m);
}
@ -983,11 +942,31 @@ static void create_overpasses(
#ifndef PRODUCT
if (TraceDefaultMethods) {
tty->print_cr("Created %d overpass methods", overpasses.length());
tty->print_cr("Created %d default methods", defaults.length());
}
#endif // ndef PRODUCT
switchover_constant_pool(&bpool, klass, &overpasses, CHECK);
merge_in_new_methods(klass, &overpasses, CHECK);
if (overpasses.length() > 0) {
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) {