mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
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:
parent
2b82651ec0
commit
088ded71f9
18 changed files with 662 additions and 248 deletions
|
@ -4080,8 +4080,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
|
|||
|
||||
// Generate any default methods - default methods are interface methods
|
||||
// that have a default implementation. This is new with Lambda project.
|
||||
if (has_default_methods && !access_flags.is_interface() &&
|
||||
local_interfaces->length() > 0) {
|
||||
if (has_default_methods && !access_flags.is_interface() ) {
|
||||
DefaultMethods::generate_default_methods(
|
||||
this_klass(), &all_mirandas, CHECK_(nullHandle));
|
||||
}
|
||||
|
|
|
@ -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,10 +619,29 @@ 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()) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
super = super->java_super();
|
||||
}
|
||||
|
||||
|
@ -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(),
|
||||
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,12 +942,32 @@ 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
|
||||
|
||||
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) {
|
||||
// Note that this must sort using the same key as is used for sorting
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -812,8 +812,8 @@ class ClassHierarchyWalker {
|
|||
Klass* k = ctxk;
|
||||
Method* lm = k->lookup_method(m->name(), m->signature());
|
||||
if (lm == NULL && k->oop_is_instance()) {
|
||||
// It might be an abstract interface method, devoid of mirandas.
|
||||
lm = ((InstanceKlass*)k)->lookup_method_in_all_interfaces(m->name(),
|
||||
// It might be an interface method
|
||||
lm = ((InstanceKlass*)k)->lookup_method_in_ordered_interfaces(m->name(),
|
||||
m->signature());
|
||||
}
|
||||
if (lm == m)
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
* 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
|
||||
|
||||
// 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) {
|
||||
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) {
|
||||
vmIntrinsics::ID iid = result_oop->intrinsic_id();
|
||||
if (MethodHandles::is_signature_polymorphic(iid)) {
|
||||
|
@ -234,6 +244,7 @@ void LinkResolver::lookup_method_in_klasses(methodHandle& result, KlassHandle kl
|
|||
}
|
||||
|
||||
// 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) {
|
||||
Method* result_oop = klass->uncached_lookup_method(name, signature);
|
||||
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());
|
||||
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;
|
||||
Symbol* name = resolved_method->name();
|
||||
Symbol* signature = resolved_method->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();
|
||||
return vt->index_of_miranda(name, signature);
|
||||
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) {
|
||||
|
@ -625,6 +661,12 @@ void LinkResolver::resolve_interface_method(methodHandle& resolved_method,
|
|||
resolved_method->method_holder()->internal_name()
|
||||
);
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -853,6 +895,7 @@ void LinkResolver::linktime_resolve_special_method(methodHandle& resolved_method
|
|||
resolved_method->signature()));
|
||||
THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
|
||||
}
|
||||
|
||||
if (TraceItables && Verbose) {
|
||||
ResourceMark rm(THREAD);
|
||||
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->access_flags().print_on(tty);
|
||||
if (resolved_method->method_holder()->is_interface() &&
|
||||
!resolved_method->is_abstract()) {
|
||||
if (resolved_method->is_default_method()) {
|
||||
tty->print("default");
|
||||
}
|
||||
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->access_flags().print_on(tty);
|
||||
if (sel_method->method_holder()->is_interface() &&
|
||||
!sel_method->is_abstract()) {
|
||||
if (sel_method->is_default_method()) {
|
||||
tty->print("default");
|
||||
}
|
||||
if (sel_method->is_overpass()) {
|
||||
tty->print("overpass");
|
||||
}
|
||||
tty->cr();
|
||||
}
|
||||
|
||||
|
@ -1007,8 +1051,7 @@ void LinkResolver::linktime_resolve_virtual_method(methodHandle &resolved_method
|
|||
resolved_method->method_holder()->internal_name()
|
||||
);
|
||||
resolved_method->access_flags().print_on(tty);
|
||||
if (resolved_method->method_holder()->is_interface() &&
|
||||
!resolved_method->is_abstract()) {
|
||||
if (resolved_method->is_default_method()) {
|
||||
tty->print("default");
|
||||
}
|
||||
if (resolved_method->is_overpass()) {
|
||||
|
@ -1045,10 +1088,8 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result,
|
|||
|
||||
// do lookup based on receiver klass using the vtable index
|
||||
if (resolved_method->method_holder()->is_interface()) { // miranda method
|
||||
vtable_index = vtable_index_of_miranda_method(resolved_klass,
|
||||
resolved_method->name(),
|
||||
resolved_method->signature(), CHECK);
|
||||
|
||||
vtable_index = vtable_index_of_interface_method(resolved_klass,
|
||||
resolved_method, CHECK);
|
||||
assert(vtable_index >= 0 , "we should have valid vtable index at this point");
|
||||
|
||||
InstanceKlass* inst = InstanceKlass::cast(recv_klass());
|
||||
|
@ -1104,11 +1145,10 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result,
|
|||
vtable_index
|
||||
);
|
||||
selected_method->access_flags().print_on(tty);
|
||||
if (selected_method->method_holder()->is_interface() &&
|
||||
!selected_method->is_abstract()) {
|
||||
if (selected_method->is_default_method()) {
|
||||
tty->print("default");
|
||||
}
|
||||
if (resolved_method->is_overpass()) {
|
||||
if (selected_method->is_overpass()) {
|
||||
tty->print("overpass");
|
||||
}
|
||||
tty->cr();
|
||||
|
@ -1191,7 +1231,6 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, methodHand
|
|||
sel_method->name(),
|
||||
sel_method->signature()));
|
||||
}
|
||||
|
||||
// check if abstract
|
||||
if (check_null_and_abstract && sel_method->is_abstract()) {
|
||||
ResourceMark rm(THREAD);
|
||||
|
@ -1220,11 +1259,10 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, methodHand
|
|||
sel_method->method_holder()->internal_name()
|
||||
);
|
||||
sel_method->access_flags().print_on(tty);
|
||||
if (sel_method->method_holder()->is_interface() &&
|
||||
!sel_method->is_abstract()) {
|
||||
if (sel_method->is_default_method()) {
|
||||
tty->print("default");
|
||||
}
|
||||
if (resolved_method->is_overpass()) {
|
||||
if (sel_method->is_overpass()) {
|
||||
tty->print("overpass");
|
||||
}
|
||||
tty->cr();
|
||||
|
|
|
@ -130,8 +130,7 @@ class LinkResolver: AllStatic {
|
|||
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);
|
||||
|
||||
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_pool (KlassHandle& resolved_klass, Symbol*& method_name, Symbol*& method_signature, KlassHandle& current_klass, constantPoolHandle pool, int index, TRAPS);
|
||||
|
|
|
@ -73,6 +73,10 @@
|
|||
"Number of bytes used by the InstanceKlass::methods() array") \
|
||||
f(method_ordering_bytes, IK_method_ordering, \
|
||||
"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, \
|
||||
"Number of bytes used by the InstanceKlass::local_interfaces() array") \
|
||||
f(transitive_interfaces_bytes, IK_transitive_interfaces, \
|
||||
|
|
|
@ -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,
|
||||
int itable_len,
|
||||
|
@ -263,6 +270,8 @@ InstanceKlass::InstanceKlass(int vtable_len,
|
|||
set_array_klasses(NULL);
|
||||
set_methods(NULL);
|
||||
set_method_ordering(NULL);
|
||||
set_default_methods(NULL);
|
||||
set_default_vtable_indices(NULL);
|
||||
set_local_interfaces(NULL);
|
||||
set_transitive_interfaces(NULL);
|
||||
init_implementor();
|
||||
|
@ -376,6 +385,21 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) {
|
|||
}
|
||||
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 place would be the only caller and it can share memory with transitive
|
||||
// interfaces.
|
||||
|
@ -1354,32 +1378,44 @@ static int binary_search(Array<Method*>* methods, Symbol* name) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
// find_method looks up the name/signature in the local methods array
|
||||
Method* InstanceKlass::find_method(Symbol* name, Symbol* signature) const {
|
||||
return InstanceKlass::find_method(methods(), name, signature);
|
||||
}
|
||||
|
||||
// find_method looks up the name/signature in the local methods array
|
||||
Method* InstanceKlass::find_method(
|
||||
Array<Method*>* methods, Symbol* name, Symbol* signature) {
|
||||
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);
|
||||
if (hit != -1) {
|
||||
Method* m = methods->at(hit);
|
||||
// Do linear search to find matching signature. First, quick check
|
||||
// for common case
|
||||
if (m->signature() == signature) return m;
|
||||
if (m->signature() == signature) return hit;
|
||||
// search downwards through overloaded methods
|
||||
int i;
|
||||
for (i = hit - 1; i >= 0; --i) {
|
||||
Method* m = methods->at(i);
|
||||
assert(m->is_method(), "must be method");
|
||||
if (m->name() != name) break;
|
||||
if (m->signature() == signature) return m;
|
||||
if (m->signature() == signature) return i;
|
||||
}
|
||||
// search upwards
|
||||
for (i = hit + 1; i < methods->length(); ++i) {
|
||||
Method* m = methods->at(i);
|
||||
assert(m->is_method(), "must be method");
|
||||
if (m->name() != name) break;
|
||||
if (m->signature() == signature) return m;
|
||||
if (m->signature() == signature) return i;
|
||||
}
|
||||
// not found
|
||||
#ifdef ASSERT
|
||||
|
@ -1387,9 +1423,8 @@ Method* InstanceKlass::find_method(
|
|||
assert(index == -1, err_msg("binary search should have found entry %d", index));
|
||||
#endif
|
||||
}
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int InstanceKlass::find_method_by_name(Symbol* name, int* end) {
|
||||
return find_method_by_name(methods(), name, end);
|
||||
}
|
||||
|
@ -1408,6 +1443,7 @@ int InstanceKlass::find_method_by_name(
|
|||
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 {
|
||||
Klass* klass = const_cast<InstanceKlass*>(this);
|
||||
while (klass != NULL) {
|
||||
|
@ -1418,6 +1454,21 @@ Method* InstanceKlass::uncached_lookup_method(Symbol* name, Symbol* signature) c
|
|||
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
|
||||
// Do NOT return private or static methods, new in JDK8 which are not externally visible
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
#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
|
||||
void InstanceKlass::add_osr_nmethod(nmethod* n) {
|
||||
// only one compilation can be active
|
||||
|
@ -2747,6 +2834,16 @@ void InstanceKlass::print_on(outputStream* st) const {
|
|||
}
|
||||
}
|
||||
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"trans. interfaces: "); transitive_interfaces()->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
|
||||
if (jni_ids() != NULL) {
|
||||
jni_ids()->verify(this);
|
||||
|
|
|
@ -269,12 +269,18 @@ class InstanceKlass: public Klass {
|
|||
|
||||
// Method array.
|
||||
Array<Method*>* _methods;
|
||||
// Default Method Array, concrete methods inherited from interfaces
|
||||
Array<Method*>* _default_methods;
|
||||
// Interface (Klass*s) this class declares locally to implement.
|
||||
Array<Klass*>* _local_interfaces;
|
||||
// Interface (Klass*s) this class implements transitively.
|
||||
Array<Klass*>* _transitive_interfaces;
|
||||
// Int array containing the original order of method in the class file (for JVMTI).
|
||||
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
|
||||
// [access, name index, sig index, initval index, low_offset, high_offset]
|
||||
// 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 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
|
||||
Array<Klass*>* local_interfaces() const { return _local_interfaces; }
|
||||
void set_local_interfaces(Array<Klass*>* a) {
|
||||
|
@ -501,12 +516,18 @@ class InstanceKlass: public Klass {
|
|||
Method* find_method(Symbol* name, Symbol* signature) const;
|
||||
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)
|
||||
Method* uncached_lookup_method(Symbol* name, Symbol* signature) const;
|
||||
|
||||
// lookup a method in all the interfaces that this class implements
|
||||
// (returns NULL if not found)
|
||||
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
|
||||
// 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
|
||||
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
|
||||
void oop_follow_contents(oop obj);
|
||||
int oop_adjust_pointers(oop obj);
|
||||
|
|
|
@ -83,7 +83,7 @@ void klassVtable::compute_vtable_size_and_num_mirandas(
|
|||
|
||||
GrowableArray<Method*> new_mirandas(20);
|
||||
// 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();
|
||||
|
||||
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*");
|
||||
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) {
|
||||
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);
|
||||
|
||||
// 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
|
||||
if (PrintVtables && Verbose) {
|
||||
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: ",
|
||||
supersuperklass->internal_name(),
|
||||
_klass->internal_name(), (target_method() != NULL) ?
|
||||
target_method()->name()->as_C_string() : "<NULL>", vtable_index);
|
||||
_klass->internal_name(), sig, vtable_index);
|
||||
super_method->access_flags().print_on(tty);
|
||||
if (super_method->is_default_method()) {
|
||||
tty->print("default");
|
||||
}
|
||||
tty->print("overriders flags: ");
|
||||
target_method->access_flags().print_on(tty);
|
||||
tty->cr();
|
||||
if (target_method->is_default_method()) {
|
||||
tty->print("default");
|
||||
}
|
||||
}
|
||||
#endif /*PRODUCT*/
|
||||
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.
|
||||
// Only called for InstanceKlass's, i.e. not for arrays
|
||||
// If that changed, could not use _klass as handle for klass
|
||||
bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle target_method, int super_vtable_len,
|
||||
bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle target_method,
|
||||
int super_vtable_len, int default_index,
|
||||
bool checkconstraints, TRAPS) {
|
||||
ResourceMark rm;
|
||||
bool allocate_new = true;
|
||||
assert(klass->oop_is_instance(), "must be InstanceKlass");
|
||||
assert(klass == target_method()->method_holder(), "caller resp.");
|
||||
|
||||
Array<int>* def_vtable_indices = NULL;
|
||||
bool is_default = false;
|
||||
// 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
|
||||
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.
|
||||
// This method will either be assigned its own itable index later,
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
@ -307,8 +357,15 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle tar
|
|||
|
||||
Symbol* name = target_method()->name();
|
||||
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++) {
|
||||
Method* super_method = method_at(i);
|
||||
// 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
|
||||
InstanceKlass* super_klass = super_method->method_holder();
|
||||
|
||||
if ((super_klass->is_override(super_method, target_loader, target_classname, THREAD)) ||
|
||||
((klass->major_version() >= VTABLE_TRANSITIVE_OVERRIDE_VERSION)
|
||||
&& ((super_klass = find_transitive_override(super_klass, target_method, i, target_loader,
|
||||
target_classname, THREAD)) != (InstanceKlass*)NULL))) {
|
||||
if (is_default
|
||||
|| ((super_klass->is_override(super_method, target_loader, target_classname, THREAD))
|
||||
|| ((klass->major_version() >= VTABLE_TRANSITIVE_OVERRIDE_VERSION)
|
||||
&& ((super_klass = find_transitive_override(super_klass,
|
||||
target_method, i, target_loader,
|
||||
target_classname, THREAD))
|
||||
!= (InstanceKlass*)NULL))))
|
||||
{
|
||||
// overriding, so no new entry
|
||||
allocate_new = false;
|
||||
|
||||
|
@ -347,7 +408,7 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle tar
|
|||
"%s used in the signature";
|
||||
char* sig = target_method()->name_and_sig_as_C_string();
|
||||
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());
|
||||
char* failed_type_name = failed_type_symbol->as_C_string();
|
||||
size_t buflen = strlen(msg) + strlen(sig) + strlen(loader1) +
|
||||
|
@ -361,15 +422,38 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle tar
|
|||
}
|
||||
|
||||
put_method_at(target_method(), 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
|
||||
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: ",
|
||||
_klass->internal_name(), (target_method() != NULL) ?
|
||||
target_method()->name()->as_C_string() : "<NULL>", i);
|
||||
target_klass->internal_name(), sig, i);
|
||||
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: ");
|
||||
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();
|
||||
}
|
||||
#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
|
||||
#ifndef PRODUCT
|
||||
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: ",
|
||||
_klass->internal_name(), (target_method() != NULL) ?
|
||||
target_method()->name()->as_C_string() : "<NULL>", i);
|
||||
target_klass->internal_name(), sig,i);
|
||||
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: ");
|
||||
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();
|
||||
}
|
||||
#endif /*PRODUCT*/
|
||||
|
@ -438,6 +535,14 @@ bool klassVtable::needs_new_vtable_entry(methodHandle target_method,
|
|||
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
|
||||
if (super == NULL) {
|
||||
return true;
|
||||
|
@ -526,26 +631,30 @@ bool klassVtable::is_miranda_entry_at(int i) {
|
|||
if (mhk->is_interface()) {
|
||||
assert(m->is_public(), "should be public");
|
||||
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 false;
|
||||
}
|
||||
|
||||
// check if a method is a miranda method, given a class's methods table and its super
|
||||
// "miranda" means not static, not defined by this class, and not defined
|
||||
// in super unless it is private and therefore inaccessible to this class.
|
||||
// check if a method is a miranda method, given a class's methods table,
|
||||
// its default_method table and its super
|
||||
// "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
|
||||
// Miranda methods only include public interface instance methods
|
||||
// Not private methods, not static methods, not default = concrete abstract
|
||||
bool klassVtable::is_miranda(Method* m, Array<Method*>* class_methods, Klass* super) {
|
||||
if (m->is_static()) {
|
||||
// Not private methods, not static methods, not default == concrete abstract
|
||||
bool klassVtable::is_miranda(Method* m, Array<Method*>* class_methods,
|
||||
Array<Method*>* default_methods, Klass* super) {
|
||||
if (m->is_static() || m->is_private()) {
|
||||
return false;
|
||||
}
|
||||
Symbol* name = m->name();
|
||||
Symbol* signature = m->signature();
|
||||
if (InstanceKlass::find_method(class_methods, name, signature) == NULL) {
|
||||
// did not find it in the method table of the current class
|
||||
if ((default_methods == NULL) ||
|
||||
InstanceKlass::find_method(default_methods, name, signature) == NULL) {
|
||||
if (super == NULL) {
|
||||
// super doesn't exist
|
||||
return true;
|
||||
|
@ -557,12 +666,13 @@ bool klassVtable::is_miranda(Method* m, Array<Method*>* class_methods, Klass* su
|
|||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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
|
||||
// not null; in addition, those that are not duplicates of miranda methods
|
||||
// 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(
|
||||
GrowableArray<Method*>* new_mirandas, GrowableArray<Method*>* all_mirandas,
|
||||
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
|
||||
int num_methods = current_interface_methods->length();
|
||||
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_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);
|
||||
// check if it is a duplicate of a super's miranda
|
||||
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,
|
||||
GrowableArray<Method*>* all_mirandas,
|
||||
Klass* super, Array<Method*>* class_methods,
|
||||
Array<Method*>* default_methods,
|
||||
Array<Klass*>* local_interfaces) {
|
||||
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++) {
|
||||
InstanceKlass *ik = InstanceKlass::cast(local_interfaces->at(i));
|
||||
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
|
||||
Array<Klass*>* super_ifs = ik->transitive_interfaces();
|
||||
int num_super_ifs = super_ifs->length();
|
||||
for (int j = 0; j < num_super_ifs; j++) {
|
||||
InstanceKlass *sik = InstanceKlass::cast(super_ifs->at(j));
|
||||
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) {
|
||||
GrowableArray<Method*> mirandas(20);
|
||||
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++) {
|
||||
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);
|
||||
++initialized;
|
||||
}
|
||||
|
@ -648,6 +776,26 @@ void klassVtable::copy_vtable_to(vtableEntry* start) {
|
|||
}
|
||||
|
||||
#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,
|
||||
int methods_length, bool * trace_name_printed) {
|
||||
// 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++) {
|
||||
if (unchecked_method_at(index) == old_method) {
|
||||
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 (!(*trace_name_printed)) {
|
||||
// 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()));
|
||||
*trace_name_printed = true;
|
||||
}
|
||||
// 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->signature()->as_C_string()));
|
||||
new_method->signature()->as_C_string(),
|
||||
updated_default ? "true" : "false"));
|
||||
}
|
||||
// cannot 'break' here; see for-loop comment above.
|
||||
}
|
||||
|
@ -701,6 +857,12 @@ void klassVtable::dump_vtable() {
|
|||
if (m != NULL) {
|
||||
tty->print(" (%5d) ", i);
|
||||
m->access_flags().print_on(tty);
|
||||
if (m->is_default_method()) {
|
||||
tty->print("default");
|
||||
}
|
||||
if (m->is_overpass()) {
|
||||
tty->print("overpass");
|
||||
}
|
||||
tty->print(" -- ");
|
||||
m->print_name(tty);
|
||||
tty->cr();
|
||||
|
@ -757,9 +919,9 @@ static int initialize_count = 0;
|
|||
// Initialization
|
||||
void klassItable::initialize_itable(bool checkconstraints, TRAPS) {
|
||||
if (_klass->is_interface()) {
|
||||
// This needs to go after vtable indexes are assigned but
|
||||
// before implementors need to know the number of itable indexes.
|
||||
assign_itable_indexes_for_interface(_klass());
|
||||
// This needs to go after vtable indices are assigned but
|
||||
// before implementors need to know the number of itable indices.
|
||||
assign_itable_indices_for_interface(_klass());
|
||||
}
|
||||
|
||||
// Cannot be setup doing bootstrapping, interfaces don't have
|
||||
|
@ -803,7 +965,7 @@ inline bool interface_method_needs_itable_index(Method* m) {
|
|||
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
|
||||
if (TraceItables) tty->print_cr("%3d: Initializing itable for interface %s", ++initialize_count,
|
||||
klass->name()->as_C_string());
|
||||
|
@ -846,7 +1008,7 @@ int klassItable::method_count_for_interface(Klass* interf) {
|
|||
}
|
||||
nof_methods -= 1;
|
||||
}
|
||||
// no methods have itable indexes
|
||||
// no methods have itable indices
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -907,6 +1069,21 @@ void klassItable::initialize_itable_for_interface(int method_table_offset, Klass
|
|||
int ime_num = m->itable_index();
|
||||
assert(ime_num < ime_count, "oob");
|
||||
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) {
|
||||
tty->print(" (%5d) ", i);
|
||||
m->access_flags().print_on(tty);
|
||||
if (m->is_default_method()) {
|
||||
tty->print("default");
|
||||
}
|
||||
tty->print(" -- ");
|
||||
m->print_name(tty);
|
||||
tty->cr();
|
||||
|
@ -1116,7 +1296,7 @@ Method* klassItable::method_for_itable_index(Klass* intf, int itable_index) {
|
|||
Array<Method*>* methods = InstanceKlass::cast(intf)->methods();
|
||||
|
||||
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;
|
||||
Method* m = methods->at(index);
|
||||
|
|
|
@ -97,6 +97,7 @@ class klassVtable : public ResourceObj {
|
|||
// trace_name_printed is set to true if the current call has
|
||||
// printed the klass name so that other routines in the adjust_*
|
||||
// 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,
|
||||
int methods_length, bool * trace_name_printed);
|
||||
bool check_no_old_or_obsolete_entries();
|
||||
|
@ -118,24 +119,28 @@ class klassVtable : public ResourceObj {
|
|||
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);
|
||||
|
||||
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,
|
||||
Handle target_loader, Symbol* target_classname, Thread* THREAD);
|
||||
|
||||
// support for miranda methods
|
||||
bool is_miranda_entry_at(int i);
|
||||
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(
|
||||
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,
|
||||
Array<Method*>* default_methods,
|
||||
Klass* super);
|
||||
static void get_mirandas(
|
||||
GrowableArray<Method*>* new_mirandas,
|
||||
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);
|
||||
inline InstanceKlass* ik() const;
|
||||
};
|
||||
|
@ -290,7 +295,7 @@ class klassItable : public ResourceObj {
|
|||
#endif // INCLUDE_JVMTI
|
||||
|
||||
// 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 compute_itable_size(Array<Klass*>* transitive_interfaces);
|
||||
static void setup_itable_offset_table(instanceKlassHandle klass);
|
||||
|
|
|
@ -511,9 +511,9 @@ bool Method::compute_has_loops_flag() {
|
|||
|
||||
bool Method::is_final_method(AccessFlags class_access_flags) const {
|
||||
// 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.
|
||||
if (is_overpass()) return false;
|
||||
if (is_overpass() || is_default_method()) return false;
|
||||
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());
|
||||
}
|
||||
|
||||
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 {
|
||||
if (is_final_method(class_access_flags)) return true;
|
||||
#ifdef ASSERT
|
||||
ResourceMark rm;
|
||||
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
|
||||
assert(valid_vtable_index() || valid_itable_index(), "method must be linked before we ask this question");
|
||||
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
|
||||
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();
|
||||
if (length > 1) {
|
||||
{
|
||||
|
@ -1379,13 +1393,14 @@ void Method::sort_methods(Array<Method*>* methods, bool idempotent) {
|
|||
QuickSort::sort<Method*>(methods->data(), length, method_comparator, idempotent);
|
||||
}
|
||||
// Reset method ordering
|
||||
if (set_idnums) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
Method* m = methods->at(i);
|
||||
m->set_method_idnum(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------
|
||||
// Non-product code unless JVM/TI needs it
|
||||
|
|
|
@ -567,6 +567,7 @@ class Method : public Metadata {
|
|||
// checks method and its method holder
|
||||
bool is_final_method() 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)
|
||||
bool can_be_statically_bound() const;
|
||||
|
@ -846,7 +847,7 @@ class Method : public Metadata {
|
|||
#endif
|
||||
|
||||
// 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
|
||||
void deallocate_contents(ClassLoaderData* loader_data);
|
||||
|
|
|
@ -1591,10 +1591,8 @@ static jmethodID get_method_id(JNIEnv *env, jclass clazz, const char *name_str,
|
|||
}
|
||||
} else {
|
||||
m = klass->lookup_method(name, signature);
|
||||
// Look up interfaces
|
||||
if (m == NULL && klass->oop_is_instance()) {
|
||||
m = InstanceKlass::cast(klass())->lookup_method_in_all_interfaces(name,
|
||||
signature);
|
||||
m = InstanceKlass::cast(klass())->lookup_method_in_ordered_interfaces(name, signature);
|
||||
}
|
||||
}
|
||||
if (m == NULL || (m->is_static() != is_static)) {
|
||||
|
|
|
@ -2755,13 +2755,26 @@ void VM_RedefineClasses::AdjustCpoolCacheAndVtable::do_klass(Klass* k) {
|
|||
// InstanceKlass around to hold obsolete methods so we don't have
|
||||
// any other InstanceKlass embedded vtables to update. The vtable
|
||||
// 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
|
||||
ResourceMark rm(_thread);
|
||||
ik->vtable()->adjust_method_entries(_matching_old_methods,
|
||||
_matching_new_methods,
|
||||
_matching_methods_length,
|
||||
&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
|
||||
|
|
|
@ -187,12 +187,34 @@ oop MethodHandles::init_method_MemberName(Handle mname, CallInfo& info) {
|
|||
receiver_limit = m->method_holder();
|
||||
assert(receiver_limit->verify_itable_index(vmindex), "");
|
||||
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;
|
||||
|
||||
case CallInfo::vtable_call:
|
||||
vmindex = info.vtable_index();
|
||||
flags |= IS_METHOD | (JVM_REF_invokeVirtual << REFERENCE_KIND_SHIFT);
|
||||
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;
|
||||
|
||||
case CallInfo::direct_call:
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -27,8 +27,11 @@
|
|||
#include "memory/universe.inline.hpp"
|
||||
#include "runtime/reflectionUtils.hpp"
|
||||
|
||||
KlassStream::KlassStream(instanceKlassHandle klass, bool local_only, bool classes_only) {
|
||||
_klass = klass;
|
||||
KlassStream::KlassStream(instanceKlassHandle klass, bool local_only,
|
||||
bool classes_only, bool walk_defaults) {
|
||||
_klass = _base_klass = klass;
|
||||
_base_class_search_defaults = false;
|
||||
_defaults_checked = false;
|
||||
if (classes_only) {
|
||||
_interfaces = Universe::the_empty_klass_array();
|
||||
} else {
|
||||
|
@ -37,6 +40,7 @@ KlassStream::KlassStream(instanceKlassHandle klass, bool local_only, bool classe
|
|||
_interface_index = _interfaces->length();
|
||||
_local_only = local_only;
|
||||
_classes_only = classes_only;
|
||||
_walk_defaults = walk_defaults;
|
||||
}
|
||||
|
||||
bool KlassStream::eos() {
|
||||
|
@ -45,7 +49,13 @@ bool KlassStream::eos() {
|
|||
if (!_klass->is_interface() && _klass->super() != NULL) {
|
||||
// go up superclass chain (not for interfaces)
|
||||
_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 {
|
||||
// Next walk transitive interfaces
|
||||
if (_interface_index > 0) {
|
||||
_klass = _interfaces->at(--_interface_index);
|
||||
} else {
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
// and (super)interfaces. Streaming is done in reverse order (subclasses first,
|
||||
// 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();
|
||||
// ...
|
||||
// }
|
||||
|
@ -46,17 +46,21 @@
|
|||
class KlassStream VALUE_OBJ_CLASS_SPEC {
|
||||
protected:
|
||||
instanceKlassHandle _klass; // current klass/interface iterated over
|
||||
instanceKlassHandle _base_klass; // initial klass/interface to iterate over
|
||||
Array<Klass*>* _interfaces; // transitive interfaces for initial class
|
||||
int _interface_index; // current interface being processed
|
||||
bool _local_only; // process initial class/interface only
|
||||
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;
|
||||
|
||||
virtual int length() const = 0;
|
||||
virtual int length() = 0;
|
||||
|
||||
public:
|
||||
// constructor
|
||||
KlassStream(instanceKlassHandle klass, bool local_only, bool classes_only);
|
||||
KlassStream(instanceKlassHandle klass, bool local_only, bool classes_only, bool walk_defaults);
|
||||
|
||||
// testing
|
||||
bool eos();
|
||||
|
@ -67,6 +71,8 @@ class KlassStream VALUE_OBJ_CLASS_SPEC {
|
|||
// accessors
|
||||
instanceKlassHandle klass() const { return _klass; }
|
||||
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 {
|
||||
private:
|
||||
int length() const { return methods()->length(); }
|
||||
Array<Method*>* methods() const { return _klass->methods(); }
|
||||
int length() { return methods()->length(); }
|
||||
Array<Method*>* methods() {
|
||||
if (base_class_search_defaults()) {
|
||||
base_class_search_defaults(false);
|
||||
return _klass->default_methods();
|
||||
} else {
|
||||
return _klass->methods();
|
||||
}
|
||||
}
|
||||
public:
|
||||
MethodStream(instanceKlassHandle klass, bool local_only, bool classes_only)
|
||||
: KlassStream(klass, local_only, classes_only) {
|
||||
: KlassStream(klass, local_only, classes_only, true) {
|
||||
_index = length();
|
||||
next();
|
||||
}
|
||||
|
||||
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 {
|
||||
private:
|
||||
int length() const { return _klass->java_fields_count(); }
|
||||
int length() { return _klass->java_fields_count(); }
|
||||
|
||||
fieldDescriptor _fd_buf;
|
||||
|
||||
public:
|
||||
FieldStream(instanceKlassHandle klass, bool local_only, bool classes_only)
|
||||
: KlassStream(klass, local_only, classes_only) {
|
||||
: KlassStream(klass, local_only, classes_only, false) {
|
||||
_index = length();
|
||||
next();
|
||||
}
|
||||
|
|
|
@ -289,6 +289,7 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
|||
nonstatic_field(ConstantPoolCache, _constant_pool, ConstantPool*) \
|
||||
nonstatic_field(InstanceKlass, _array_klasses, Klass*) \
|
||||
nonstatic_field(InstanceKlass, _methods, Array<Method*>*) \
|
||||
nonstatic_field(InstanceKlass, _default_methods, Array<Method*>*) \
|
||||
nonstatic_field(InstanceKlass, _local_interfaces, Array<Klass*>*) \
|
||||
nonstatic_field(InstanceKlass, _transitive_interfaces, Array<Klass*>*) \
|
||||
nonstatic_field(InstanceKlass, _fields, Array<u2>*) \
|
||||
|
@ -323,6 +324,7 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
|||
nonstatic_field(nmethodBucket, _count, int) \
|
||||
nonstatic_field(nmethodBucket, _next, nmethodBucket*) \
|
||||
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, _secondary_super_cache, Klass*) \
|
||||
nonstatic_field(Klass, _secondary_supers, Array<Klass*>*) \
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue