Mercurial > hg > graal-compiler
diff src/share/vm/classfile/defaultMethods.cpp @ 13086:096c224171c4
Merge with http://hg.openjdk.java.net/hsx/hsx25/hotspot/
author | Doug Simon <doug.simon@oracle.com> |
---|---|
date | Wed, 20 Nov 2013 00:10:38 +0100 |
parents | cefad50507d8 fce21ac5968d |
children | 02f27ecb4f3a |
line wrap: on
line diff
--- a/src/share/vm/classfile/defaultMethods.cpp Tue Nov 19 17:44:26 2013 +0100 +++ b/src/share/vm/classfile/defaultMethods.cpp Wed Nov 20 00:10:38 2013 +0100 @@ -171,8 +171,12 @@ } bool is_cancelled() const { return _cancelled; } + // This code used to skip interface classes because their only + // superclass was j.l.Object which would be also covered by class + // superclass hierarchy walks. Now that the starting point can be + // an interface, we must ensure we catch j.l.Object as the super. static bool has_super(InstanceKlass* cls) { - return cls->super() != NULL && !cls->is_interface(); + return cls->super() != NULL; } Node* node_at_depth(int i) const { @@ -345,7 +349,6 @@ } 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: @@ -392,32 +395,40 @@ return; } + // Qualified methods are maximally-specific methods + // These include public, instance concrete (=default) and abstract methods GrowableArray<Method*> qualified_methods; + int num_defaults = 0; + int default_index = -1; + int qualified_index = -1; for (int i = 0; i < _members.length(); ++i) { Pair<Method*,QualifiedState> entry = _members.at(i); if (entry.second == QUALIFIED) { qualified_methods.append(entry.first); + qualified_index++; + if (entry.first->is_default_method()) { + num_defaults++; + default_index = qualified_index; + + } } } if (qualified_methods.length() == 0) { _exception_message = generate_no_defaults_message(CHECK); _exception_name = vmSymbols::java_lang_AbstractMethodError(); - } else if (qualified_methods.length() == 1) { - 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 { - _selected_target = qualified_methods.at(0); - } - } else { + // If only one qualified method is default, select that + } else if (num_defaults == 1) { + _selected_target = qualified_methods.at(default_index); + } else if (num_defaults > 1) { _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"); + // leave abstract methods alone, they will be found via normal search path } bool contains_signature(Symbol* query) { @@ -475,20 +486,6 @@ 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 +592,18 @@ #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 +613,10 @@ // 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 +632,26 @@ // 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)); + } } } } @@ -678,8 +708,10 @@ Method* m = iklass->find_method(_method_name, _method_signature); // private interface methods are not candidates for default methods // invokespecial to private interface methods doesn't use default method logic + // The overpasses are your supertypes' errors, we do not include them // future: take access controls into account for superclass methods - if (m != NULL && (!iklass->is_interface() || m->is_public())) { + if (m != NULL && !m->is_static() && !m->is_overpass() && + (!iklass->is_interface() || m->is_public())) { if (_family == NULL) { _family = new StatefulMethodFamily(); } @@ -700,7 +732,7 @@ -static void create_overpasses( +static void create_defaults_and_exceptions( GrowableArray<EmptyVtableSlot*>* slots, InstanceKlass* klass, TRAPS); static void generate_erased_defaults( @@ -721,6 +753,8 @@ 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. @@ -753,7 +787,8 @@ #ifndef PRODUCT if (TraceDefaultMethods) { ResourceMark rm; // be careful with these! - tty->print_cr("Class %s requires default method processing", + tty->print_cr("%s %s requires default method processing", + klass->is_interface() ? "Interface" : "Class", klass->name()->as_klass_external_name()); PrintHierarchy printer; printer.run(klass); @@ -778,11 +813,11 @@ } #ifndef PRODUCT if (TraceDefaultMethods) { - tty->print_cr("Creating overpasses..."); + tty->print_cr("Creating defaults and overpasses..."); } #endif // ndef PRODUCT - create_overpasses(empty_slots, klass, CHECK); + create_defaults_and_exceptions(empty_slots, klass, CHECK); #ifndef PRODUCT if (TraceDefaultMethods) { @@ -791,66 +826,6 @@ #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) { @@ -898,7 +873,6 @@ m->set_max_locals(params); m->constMethod()->set_stackmap_data(NULL); m->set_code(code_start); - m->set_force_inline(true); return m; } @@ -924,18 +898,18 @@ } } -// 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 +917,6 @@ if (slot->is_bound()) { MethodFamily* method = slot->get_binding(); - int max_stack = 0; BytecodeBuffer buffer; #ifndef PRODUCT @@ -953,26 +926,27 @@ 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 +957,31 @@ #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) { @@ -1089,7 +1083,9 @@ klass->set_initial_method_idnum(new_size); ClassLoaderData* cld = klass->class_loader_data(); - MetadataFactory::free_array(cld, original_methods); + if (original_methods ->length() > 0) { + MetadataFactory::free_array(cld, original_methods); + } if (original_ordering->length() > 0) { klass->set_method_ordering(merged_ordering); MetadataFactory::free_array(cld, original_ordering);