8221470: Print methods in exception messages in java-like Syntax

Reviewed-by: dholmes, mdoerr, coleenp
This commit is contained in:
Goetz Lindenmaier 2019-04-04 09:39:44 +02:00
parent 6780d21dd6
commit 39f3368ffd
22 changed files with 470 additions and 161 deletions

View file

@ -2060,7 +2060,9 @@ void ClassVerifier::class_format_error(const char* msg, ...) {
ss.vprint(msg, va);
va_end(va);
if (!_method.is_null()) {
ss.print(" in method %s", _method->name_and_sig_as_C_string());
ss.print(" in method '");
_method->print_external_name(&ss);
ss.print("'");
}
_message = ss.as_string();
}

View file

@ -264,10 +264,6 @@ LinkInfo::LinkInfo(const constantPoolHandle& pool, int index, TRAPS) {
_check_access = true;
}
char* LinkInfo::method_string() const {
return Method::name_and_sig_as_C_string(_resolved_klass, _name, _signature);
}
#ifndef PRODUCT
void LinkInfo::print() {
ResourceMark rm;
@ -593,14 +589,12 @@ void LinkResolver::check_method_accessability(Klass* ref_klass,
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_IllegalAccessError(),
"class %s tried to access %s%s%smethod %s.%s%s (%s%s%s)",
"class %s tried to access %s%s%smethod '%s' (%s%s%s)",
ref_klass->external_name(),
sel_method->is_abstract() ? "abstract " : "",
sel_method->is_protected() ? "protected " : "",
sel_method->is_private() ? "private " : "",
sel_klass->external_name(),
sel_method->name()->as_C_string(),
sel_method->signature()->as_C_string(),
sel_method->external_name(),
(same_module) ? ref_klass->joint_in_module_of_loader(sel_klass) : ref_klass->class_in_module_of_loader(),
(same_module) ? "" : "; ",
(same_module) ? "" : sel_klass->class_in_module_of_loader()
@ -670,12 +664,11 @@ void LinkResolver::check_method_loader_constraints(const LinkInfo& link_info,
assert(target_loader_data != NULL, "resolved method's class has no class loader data");
stringStream ss;
ss.print("loader constraint violation: when resolving %s"
" \"%s\" the class loader %s of the current class, %s,"
ss.print("loader constraint violation: when resolving %s '", method_type);
Method::print_external_name(&ss, link_info.resolved_klass(), link_info.name(), link_info.signature());
ss.print("' the class loader %s of the current class, %s,"
" and the class loader %s for the method's defining class, %s, have"
" different Class objects for the type %s used in the signature (%s; %s)",
method_type,
link_info.method_string(),
current_loader_data->loader_name_and_id(),
current_class->name()->as_C_string(),
target_loader_data->loader_name_and_id(),
@ -739,9 +732,11 @@ methodHandle LinkResolver::resolve_method(const LinkInfo& link_info,
// 2. check constant pool tag for called method - must be JVM_CONSTANT_Methodref
if (!link_info.tag().is_invalid() && !link_info.tag().is_method()) {
ResourceMark rm(THREAD);
char buf[200];
jio_snprintf(buf, sizeof(buf), "Method %s must be Methodref constant", link_info.method_string());
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
stringStream ss;
ss.print("Method '");
Method::print_external_name(&ss, link_info.resolved_klass(), link_info.name(), link_info.signature());
ss.print("' must be Methodref constant");
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string());
}
// 3. lookup method in resolved klass and its super klasses
@ -764,11 +759,12 @@ methodHandle LinkResolver::resolve_method(const LinkInfo& link_info,
// 5. method lookup failed
if (resolved_method.is_null()) {
ResourceMark rm(THREAD);
stringStream ss;
ss.print("'");
Method::print_external_name(&ss, resolved_klass, link_info.name(), link_info.signature());
ss.print("'");
THROW_MSG_CAUSE_(vmSymbols::java_lang_NoSuchMethodError(),
Method::name_and_sig_as_C_string(resolved_klass,
link_info.name(),
link_info.signature()),
nested_exception, NULL);
ss.as_string(), nested_exception, NULL);
}
// 6. access checks, access checking may be turned off when calling from within the VM.
@ -840,9 +836,11 @@ methodHandle LinkResolver::resolve_interface_method(const LinkInfo& link_info, B
// check constant pool tag for called method - must be JVM_CONSTANT_InterfaceMethodref
if (!link_info.tag().is_invalid() && !link_info.tag().is_interface_method()) {
ResourceMark rm(THREAD);
char buf[200];
jio_snprintf(buf, sizeof(buf), "Method %s must be InterfaceMethodref constant", link_info.method_string());
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
stringStream ss;
ss.print("Method '");
Method::print_external_name(&ss, link_info.resolved_klass(), link_info.name(), link_info.signature());
ss.print("' must be InterfaceMethodref constant");
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string());
}
// lookup method in this interface or its super, java.lang.Object
@ -857,10 +855,11 @@ methodHandle LinkResolver::resolve_interface_method(const LinkInfo& link_info, B
if (resolved_method.is_null()) {
// no method found
ResourceMark rm(THREAD);
THROW_MSG_NULL(vmSymbols::java_lang_NoSuchMethodError(),
Method::name_and_sig_as_C_string(resolved_klass,
link_info.name(),
link_info.signature()));
stringStream ss;
ss.print("'");
Method::print_external_name(&ss, resolved_klass, link_info.name(), link_info.signature());
ss.print("'");
THROW_MSG_NULL(vmSymbols::java_lang_NoSuchMethodError(), ss.as_string());
}
if (link_info.check_access()) {
@ -881,11 +880,12 @@ methodHandle LinkResolver::resolve_interface_method(const LinkInfo& link_info, B
if (code != Bytecodes::_invokestatic && resolved_method->is_static()) {
ResourceMark rm(THREAD);
char buf[200];
jio_snprintf(buf, sizeof(buf), "Expected instance not static method %s",
Method::name_and_sig_as_C_string(resolved_klass,
resolved_method->name(), resolved_method->signature()));
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
stringStream ss;
ss.print("Expected instance not static method '");
Method::print_external_name(&ss, resolved_klass,
resolved_method->name(), resolved_method->signature());
ss.print("'");
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string());
}
if (log_develop_is_enabled(Trace, itables)) {
@ -1086,11 +1086,11 @@ methodHandle LinkResolver::linktime_resolve_static_method(const LinkInfo& link_i
// check if static
if (!resolved_method->is_static()) {
ResourceMark rm(THREAD);
char buf[200];
jio_snprintf(buf, sizeof(buf), "Expected static method %s", Method::name_and_sig_as_C_string(resolved_klass,
resolved_method->name(),
resolved_method->signature()));
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
stringStream ss;
ss.print("Expected static method '");
resolved_method()->print_external_name(&ss);
ss.print("'");
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string());
}
return resolved_method;
}
@ -1127,14 +1127,16 @@ methodHandle LinkResolver::linktime_resolve_special_method(const LinkInfo& link_
if (resolved_method->name() == vmSymbols::object_initializer_name() &&
resolved_method->method_holder() != resolved_klass) {
ResourceMark rm(THREAD);
stringStream ss;
ss.print("%s: method '", resolved_klass->external_name());
resolved_method->signature()->print_as_signature_external_return_type(&ss);
ss.print(" %s(", resolved_method->name()->as_C_string());
resolved_method->signature()->print_as_signature_external_parameters(&ss);
ss.print(")' not found");
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_NoSuchMethodError(),
"%s: method %s%s not found",
resolved_klass->external_name(),
resolved_method->name()->as_C_string(),
resolved_method->signature()->as_C_string()
);
"%s", ss.as_string());
return NULL;
}
@ -1153,27 +1155,23 @@ methodHandle LinkResolver::linktime_resolve_special_method(const LinkInfo& link_
if (!is_reflect &&
!klass_to_check->is_same_or_direct_interface(resolved_klass)) {
ResourceMark rm(THREAD);
char buf[200];
jio_snprintf(buf, sizeof(buf),
"Interface method reference: %s, is in an indirect superinterface of %s",
Method::name_and_sig_as_C_string(resolved_klass,
resolved_method->name(),
resolved_method->signature()),
current_klass->external_name());
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
stringStream ss;
ss.print("Interface method reference: '");
resolved_method->print_external_name(&ss);
ss.print("', is in an indirect superinterface of %s",
current_klass->external_name());
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string());
}
}
// check if not static
if (resolved_method->is_static()) {
ResourceMark rm(THREAD);
char buf[200];
jio_snprintf(buf, sizeof(buf),
"Expecting non-static method %s",
Method::name_and_sig_as_C_string(resolved_klass,
resolved_method->name(),
resolved_method->signature()));
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
stringStream ss;
ss.print("Expecting non-static method '");
resolved_method->print_external_name(&ss);
ss.print("'");
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string());
}
if (log_develop_is_enabled(Trace, itables)) {
@ -1219,10 +1217,11 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result,
// check if found
if (sel_method.is_null()) {
ResourceMark rm(THREAD);
THROW_MSG(vmSymbols::java_lang_AbstractMethodError(),
Method::name_and_sig_as_C_string(resolved_klass,
resolved_method->name(),
resolved_method->signature()));
stringStream ss;
ss.print("'");
resolved_method->print_external_name(&ss);
ss.print("'");
THROW_MSG(vmSymbols::java_lang_AbstractMethodError(), ss.as_string());
// check loader constraints if found a different method
} else if (sel_method() != resolved_method()) {
check_method_loader_constraints(link_info, sel_method, "method", CHECK);
@ -1244,8 +1243,8 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result,
char buf[500];
jio_snprintf(buf, sizeof(buf),
"Receiver class %s must be the current class or a subtype of interface %s",
receiver_klass->name()->as_C_string(),
sender->name()->as_C_string());
receiver_klass->external_name(),
sender->external_name());
THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), buf);
}
}
@ -1254,20 +1253,21 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result,
// check if not static
if (sel_method->is_static()) {
ResourceMark rm(THREAD);
char buf[200];
jio_snprintf(buf, sizeof(buf), "Expecting non-static method %s", Method::name_and_sig_as_C_string(resolved_klass,
resolved_method->name(),
resolved_method->signature()));
THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
stringStream ss;
ss.print("Expecting non-static method '");
resolved_method->print_external_name(&ss);
ss.print("'");
THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string());
}
// check if abstract
if (sel_method->is_abstract()) {
ResourceMark rm(THREAD);
THROW_MSG(vmSymbols::java_lang_AbstractMethodError(),
Method::name_and_sig_as_C_string(resolved_klass,
sel_method->name(),
sel_method->signature()));
stringStream ss;
ss.print("'");
Method::print_external_name(&ss, resolved_klass, sel_method->name(), sel_method->signature());
ss.print("'");
THROW_MSG(vmSymbols::java_lang_AbstractMethodError(), ss.as_string());
}
if (log_develop_is_enabled(Trace, itables)) {
@ -1305,23 +1305,22 @@ methodHandle LinkResolver::linktime_resolve_virtual_method(const LinkInfo& link_
// This is impossible, if resolve_klass is an interface, we've thrown icce in resolve_method
if (resolved_klass->is_interface() && resolved_method->is_private()) {
ResourceMark rm(THREAD);
char buf[200];
jio_snprintf(buf, sizeof(buf), "private interface method requires invokespecial, not invokevirtual: method %s, caller-class:%s",
Method::name_and_sig_as_C_string(resolved_klass,
resolved_method->name(),
resolved_method->signature()),
(current_klass == NULL ? "<NULL>" : current_klass->internal_name()));
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
stringStream ss;
ss.print("private interface method requires invokespecial, not invokevirtual: method '");
resolved_method->print_external_name(&ss);
ss.print("', caller-class: %s",
(current_klass == NULL ? "<null>" : current_klass->internal_name()));
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string());
}
// check if not static
if (resolved_method->is_static()) {
ResourceMark rm(THREAD);
char buf[200];
jio_snprintf(buf, sizeof(buf), "Expecting non-static method %s", Method::name_and_sig_as_C_string(resolved_klass,
resolved_method->name(),
resolved_method->signature()));
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
stringStream ss;
ss.print("Expecting non-static method '");
resolved_method->print_external_name(&ss);
ss.print("'");
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string());
}
if (log_develop_is_enabled(Trace, vtables)) {
@ -1470,10 +1469,11 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result,
// Throw Illegal Access Error if selected_method is not public.
if (!selected_method->is_public()) {
ResourceMark rm(THREAD);
THROW_MSG(vmSymbols::java_lang_IllegalAccessError(),
Method::name_and_sig_as_C_string(recv_klass,
selected_method->name(),
selected_method->signature()));
stringStream ss;
ss.print("'");
Method::print_external_name(&ss, recv_klass, selected_method->name(), selected_method->signature());
ss.print("'");
THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), ss.as_string());
}
// check if abstract
if (check_null_and_abstract && selected_method->is_abstract()) {
@ -1806,19 +1806,22 @@ void LinkResolver::throw_abstract_method_error(const methodHandle& resolved_meth
}
assert(resolved_method.not_null(), "Sanity");
ss.print(" resolved method %s%s%s%s of %s %s.",
ss.print(" resolved method '%s%s",
resolved_method->is_abstract() ? "abstract " : "",
resolved_method->is_private() ? "private " : "",
resolved_method->name()->as_C_string(),
resolved_method->signature()->as_C_string(),
resolved_method->is_private() ? "private " : "");
resolved_method->signature()->print_as_signature_external_return_type(&ss);
ss.print(" %s(", resolved_method->name()->as_C_string());
resolved_method->signature()->print_as_signature_external_parameters(&ss);
ss.print(")' of %s %s.",
resolved_klass->external_kind(),
resolved_klass->external_name());
if (selected_method.not_null() && !(resolved_method == selected_method)) {
ss.print(" Selected method is %s%s%s.",
ss.print(" Selected method is '%s%s",
selected_method->is_abstract() ? "abstract " : "",
selected_method->is_private() ? "private " : "",
selected_method->name_and_sig_as_C_string());
selected_method->is_private() ? "private " : "");
selected_method->print_external_name(&ss);
ss.print("'.");
}
THROW_MSG(vmSymbols::java_lang_AbstractMethodError(), ss.as_string());

View file

@ -182,7 +182,6 @@ class LinkInfo : public StackObj {
methodHandle current_method() const { return _current_method; }
constantTag tag() const { return _tag; }
bool check_access() const { return _check_access; }
char* method_string() const;
void print() PRODUCT_RETURN;
};

View file

@ -1000,14 +1000,17 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp,
if ((callee->is_interface() && m_tag.is_method()) ||
((!callee->is_interface() && m_tag.is_interface_method()))) {
ResourceMark rm(THREAD);
char buf[400];
jio_snprintf(buf, sizeof(buf),
"Inconsistent constant pool data in classfile for class %s. "
"Method %s%s at index %d is %s and should be %s",
callee->name()->as_C_string(), name->as_C_string(), signature->as_C_string(), index,
callee->is_interface() ? "CONSTANT_MethodRef" : "CONSTANT_InterfaceMethodRef",
callee->is_interface() ? "CONSTANT_InterfaceMethodRef" : "CONSTANT_MethodRef");
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
stringStream ss;
ss.print("Inconsistent constant pool data in classfile for class %s. "
"Method '", callee->name()->as_C_string());
signature->print_as_signature_external_return_type(&ss);
ss.print(" %s(", name->as_C_string());
signature->print_as_signature_external_parameters(&ss);
ss.print(")' at index %d is %s and should be %s",
index,
callee->is_interface() ? "CONSTANT_MethodRef" : "CONSTANT_InterfaceMethodRef",
callee->is_interface() ? "CONSTANT_InterfaceMethodRef" : "CONSTANT_MethodRef");
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string());
}
Klass* klass = this_cp->pool_holder();

View file

@ -500,11 +500,11 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, const methodHand
if (failed_type_symbol != NULL) {
stringStream ss;
ss.print("loader constraint violation for class %s: when selecting "
"overriding method %s the class loader %s of the "
"overriding method '", klass->external_name());
target_method()->print_external_name(&ss),
ss.print("' the class loader %s of the "
"selected method's type %s, and the class loader %s for its super "
"type %s have different Class objects for the type %s used in the signature (%s; %s)",
klass->external_name(),
target_method()->name_and_sig_as_C_string(),
target_klass->class_loader_data()->loader_name_and_id(),
target_klass->external_name(),
super_klass->class_loader_data()->loader_name_and_id(),
@ -1227,15 +1227,16 @@ void klassItable::initialize_itable_for_interface(int method_table_offset, Insta
if (failed_type_symbol != NULL) {
stringStream ss;
ss.print("loader constraint violation in interface itable"
" initialization for class %s: when selecting method %s the"
" class loader %s for super interface %s, and the class"
" loader %s of the selected method's type, %s have"
" initialization for class %s: when selecting method '",
_klass->external_name());
m->print_external_name(&ss),
ss.print("' the class loader %s for super interface %s, and the class"
" loader %s of the selected method's %s, %s have"
" different Class objects for the type %s used in the signature (%s; %s)",
_klass->external_name(),
m->name_and_sig_as_C_string(),
interf->class_loader_data()->loader_name_and_id(),
interf->external_name(),
target()->method_holder()->class_loader_data()->loader_name_and_id(),
target()->method_holder()->external_kind(),
target()->method_holder()->external_name(),
failed_type_symbol->as_klass_external_name(),
interf->class_in_module_of_loader(false, true),

View file

@ -178,6 +178,27 @@ char* Method::name_and_sig_as_C_string(Klass* klass, Symbol* method_name, Symbol
return buf;
}
const char* Method::external_name() const {
return external_name(constants()->pool_holder(), name(), signature());
}
void Method::print_external_name(outputStream *os) const {
print_external_name(os, constants()->pool_holder(), name(), signature());
}
const char* Method::external_name(Klass* klass, Symbol* method_name, Symbol* signature) {
stringStream ss;
print_external_name(&ss, klass, method_name, signature);
return ss.as_string();
}
void Method::print_external_name(outputStream *os, Klass* klass, Symbol* method_name, Symbol* signature) {
signature->print_as_signature_external_return_type(os);
os->print(" %s.%s(", klass->external_name(), method_name->as_C_string());
signature->print_as_signature_external_parameters(os);
os->print(")");
}
int Method::fast_exception_handler_bci_for(const methodHandle& mh, Klass* ex_klass, int throw_bci, TRAPS) {
// exception table holds quadruple entries of the form (beg_bci, end_bci, handler_bci, klass_index)
// access exception table

View file

@ -180,8 +180,8 @@ class Method : public Metadata {
}
// Helper routine: get klass name + "." + method name + signature as
// C string, for the purpose of providing more useful NoSuchMethodErrors
// and fatal error handling. The string is allocated in resource
// C string, for the purpose of providing more useful
// fatal error handling. The string is allocated in resource
// area if a buffer is not provided by the caller.
char* name_and_sig_as_C_string() const;
char* name_and_sig_as_C_string(char* buf, int size) const;
@ -190,6 +190,18 @@ class Method : public Metadata {
static char* name_and_sig_as_C_string(Klass* klass, Symbol* method_name, Symbol* signature);
static char* name_and_sig_as_C_string(Klass* klass, Symbol* method_name, Symbol* signature, char* buf, int size);
// Get return type + klass name + "." + method name + ( parameters types )
// as a C string or print it to an outputStream.
// This is to be used to assemble strings passed to Java, so that
// the text more resembles Java code. Used in exception messages.
// Memory is allocated in the resource area; the caller needs
// a ResourceMark.
const char* external_name() const;
void print_external_name(outputStream *os) const;
static const char* external_name( Klass* klass, Symbol* method_name, Symbol* signature);
static void print_external_name(outputStream *os, Klass* klass, Symbol* method_name, Symbol* signature);
Bytecodes::Code java_code_at(int bci) const {
return Bytecodes::java_code_at(this, bcp_from(bci));
}

View file

@ -200,6 +200,66 @@ const char* Symbol::as_klass_external_name() const {
return str;
}
static void print_class(outputStream *os, char *class_str, int len) {
for (int i = 0; i < len; ++i) {
if (class_str[i] == '/') {
os->put('.');
} else {
os->put(class_str[i]);
}
}
}
static void print_array(outputStream *os, char *array_str, int len) {
int dimensions = 0;
for (int i = 0; i < len; ++i) {
if (array_str[i] == '[') {
dimensions++;
} else if (array_str[i] == 'L') {
// Expected format: L<type name>;. Skip 'L' and ';' delimiting the type name.
print_class(os, array_str+i+1, len-i-2);
break;
} else {
os->print("%s", type2name(char2type(array_str[i])));
}
}
for (int i = 0; i < dimensions; ++i) {
os->print("[]");
}
}
void Symbol::print_as_signature_external_return_type(outputStream *os) {
for (SignatureStream ss(this); !ss.is_done(); ss.next()) {
if (ss.at_return_type()) {
if (ss.is_array()) {
print_array(os, (char*)ss.raw_bytes(), (int)ss.raw_length());
} else if (ss.is_object()) {
// Expected format: L<type name>;. Skip 'L' and ';' delimiting the class name.
print_class(os, (char*)ss.raw_bytes()+1, (int)ss.raw_length()-2);
} else {
os->print("%s", type2name(ss.type()));
}
}
}
}
void Symbol::print_as_signature_external_parameters(outputStream *os) {
bool first = true;
for (SignatureStream ss(this); !ss.is_done(); ss.next()) {
if (ss.at_return_type()) break;
if (!first) { os->print(", "); }
if (ss.is_array()) {
print_array(os, (char*)ss.raw_bytes(), (int)ss.raw_length());
} else if (ss.is_object()) {
// Skip 'L' and ';'.
print_class(os, (char*)ss.raw_bytes()+1, (int)ss.raw_length()-2);
} else {
os->print("%s", type2name(ss.type()));
}
first = false;
}
}
// Increment refcount while checking for zero. If the Symbol's refcount becomes zero
// a thread could be concurrently removing the Symbol. This is used during SymbolTable
// lookup to avoid reviving a dead Symbol.

View file

@ -229,6 +229,15 @@ class Symbol : public MetaspaceObj {
const char* as_klass_external_name() const;
const char* as_klass_external_name(char* buf, int size) const;
// Treating the symbol as a signature, print the return
// type to the outputStream. Prints external names as 'double' or
// 'java.lang.Object[][]'.
void print_as_signature_external_return_type(outputStream *os);
// Treating the symbol as a signature, print the parameter types
// seperated by ', ' to the outputStream. Prints external names as
// 'double' or 'java.lang.Object[][]'.
void print_as_signature_external_parameters(outputStream *os);
void metaspace_pointers_do(MetaspaceClosure* it);
MetaspaceObj::Type type() const { return SymbolType; }

View file

@ -2955,8 +2955,9 @@ static bool register_native(Klass* k, Symbol* name, Symbol* signature, address e
if (method == NULL) {
ResourceMark rm;
stringStream st;
st.print("Method %s name or signature does not match",
Method::name_and_sig_as_C_string(k, name, signature));
st.print("Method '");
Method::print_external_name(&st, k, name, signature);
st.print("' name or signature does not match");
THROW_MSG_(vmSymbols::java_lang_NoSuchMethodError(), st.as_string(), false);
}
if (!method->is_native()) {
@ -2965,8 +2966,9 @@ static bool register_native(Klass* k, Symbol* name, Symbol* signature, address e
if (method == NULL) {
ResourceMark rm;
stringStream st;
st.print("Method %s is not declared as native",
Method::name_and_sig_as_C_string(k, name, signature));
st.print("Method '");
Method::print_external_name(&st, k, name, signature);
st.print("' is not declared as native");
THROW_MSG_(vmSymbols::java_lang_NoSuchMethodError(), st.as_string(), false);
}
}

View file

@ -380,8 +380,11 @@ address NativeLookup::lookup_base(const methodHandle& method, bool& in_base_libr
if (entry != NULL) return entry;
// Native function not found, throw UnsatisfiedLinkError
THROW_MSG_0(vmSymbols::java_lang_UnsatisfiedLinkError(),
method->name_and_sig_as_C_string());
stringStream ss;
ss.print("'");
method->print_external_name(&ss);
ss.print("'");
THROW_MSG_0(vmSymbols::java_lang_UnsatisfiedLinkError(), ss.as_string());
}

View file

@ -151,8 +151,8 @@ int StackWalk::fill_in_frames(jlong mode, BaseFrameStream& stream,
index == start_index && method->caller_sensitive()) {
ResourceMark rm(THREAD);
THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(),
err_msg("StackWalker::getCallerClass called from @CallerSensitive %s method",
method->name_and_sig_as_C_string()));
err_msg("StackWalker::getCallerClass called from @CallerSensitive '%s' method",
method->external_name()));
}
// fill in StackFrameInfo and initialize MemberName
stream.fill_frame(index, frames_array, method, CHECK_0);

View file

@ -1085,11 +1085,12 @@ static oop invoke(InstanceKlass* klass,
if (method->is_abstract()) {
// new default: 6531596
ResourceMark rm(THREAD);
stringStream ss;
ss.print("'");
Method::print_external_name(&ss, target_klass, method->name(), method->signature());
ss.print("'");
Handle h_origexception = Exceptions::new_exception(THREAD,
vmSymbols::java_lang_AbstractMethodError(),
Method::name_and_sig_as_C_string(target_klass,
method->name(),
method->signature()));
vmSymbols::java_lang_AbstractMethodError(), ss.as_string());
JavaCallArguments args(h_origexception);
THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(),
vmSymbols::throwable_void_signature(),
@ -1104,10 +1105,13 @@ static oop invoke(InstanceKlass* klass,
// an internal vtable bug. If you ever get this please let Karen know.
if (method.is_null()) {
ResourceMark rm(THREAD);
THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(),
Method::name_and_sig_as_C_string(klass,
reflected_method->name(),
reflected_method->signature()));
stringStream ss;
ss.print("'");
Method::print_external_name(&ss, klass,
reflected_method->name(),
reflected_method->signature());
ss.print("'");
THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(), ss.as_string());
}
assert(ptypes->is_objArray(), "just checking");

View file

@ -38,19 +38,19 @@ public class Test {
// Break expected error messages into 3 parts since the loader name includes its identity
// hash which is unique and can't be compared against.
static String expectedErrorMessage1_part1 = "loader constraint violation in interface itable initialization for " +
"class test.C: when selecting method test.I.m()Ltest/Foo; the class loader " +
"class test.C: when selecting method 'test.Foo test.I.m()' the class loader " +
"PreemptingClassLoader @";
static String expectedErrorMessage1_part2 = " for super interface test.I, and the class loader 'app' of the " +
"selected method's type, test.J have different Class objects for the " +
"selected method's interface, test.J have different Class objects for the " +
"type test.Foo used in the signature (test.I is in unnamed module of loader " +
"PreemptingClassLoader @";
static String expectedErrorMessage1_part3 = ", parent loader 'app'; test.J is in unnamed module of loader 'app')";
static String expectedErrorMessage2_part1 = "loader constraint violation in interface itable initialization for " +
"class test.C: when selecting method test.I.m()Ltest/Foo; the class loader " +
"class test.C: when selecting method 'test.Foo test.I.m()' the class loader " +
"'ItableLdrCnstrnt_Test_Loader' @";
static String expectedErrorMessage2_part2 = " for super interface test.I, and the class loader 'app' of the " +
"selected method's type, test.J have different Class objects for the " +
"selected method's interface, test.J have different Class objects for the " +
"type test.Foo used in the signature (test.I is in unnamed module of loader " +
"'ItableLdrCnstrnt_Test_Loader' @";
static String expectedErrorMessage2_part3 = ", parent loader 'app'; test.J is in unnamed module of loader 'app')";
@ -79,7 +79,9 @@ public class Test {
if (!errorMsg.contains(expectedErrorMessage_part1) ||
!errorMsg.contains(expectedErrorMessage_part2) ||
!errorMsg.contains(expectedErrorMessage_part3)) {
System.out.println("Expected: " + expectedErrorMessage_part1 + "<id>" + expectedErrorMessage_part2 + "\n" +
System.out.println("Expected: " + expectedErrorMessage_part1 + "<id>" +
expectedErrorMessage_part2 + "<id>" +
expectedErrorMessage_part3 + "\n" +
"but got: " + errorMsg);
throw new RuntimeException("Wrong LinkageError exception thrown: " + errorMsg);
}

View file

@ -38,7 +38,7 @@ public class Test {
// Break expected error messages into 3 parts since the loader name includes its identity
// hash which is unique and can't be compared against.
static String expectedErrorMessage1_part1 = "loader constraint violation for class test.Task: when " +
"selecting overriding method test.Task.m()Ltest/Foo; the " +
"selecting overriding method 'test.Foo test.Task.m()' the " +
"class loader PreemptingClassLoader @";
static String expectedErrorMessage1_part2 = " of the selected method's type test.Task, and the class " +
"loader 'app' for its super type test.J have different Class objects " +
@ -47,7 +47,7 @@ public class Test {
static String expectedErrorMessage1_part3 = ", parent loader 'app'; test.J is in unnamed module of loader 'app')";
static String expectedErrorMessage2_part1 = "loader constraint violation for class test.Task: when " +
"selecting overriding method test.Task.m()Ltest/Foo; the " +
"selecting overriding method 'test.Foo test.Task.m()' the " +
"class loader 'VtableLdrCnstrnt_Test_Loader' @";
static String expectedErrorMessage2_part2 = " of the selected method's type test.Task, and the class " +
"loader 'app' for its super type test.J have different Class objects " +

View file

@ -671,7 +671,7 @@ public class TestNestmateMembership {
static void test_NoHostInvoke() throws Throwable {
System.out.println("Testing for missing nest-host attribute");
String msg = "class TestNestmateMembership$Caller tried to access " +
"private method TestNestmateMembership$TargetNoHost.m()V";
"private method 'void TestNestmateMembership$TargetNoHost.m()'";
try {
Caller.invokeTargetNoHost();
throw new Error("Missing IllegalAccessError: " + msg);
@ -698,7 +698,7 @@ public class TestNestmateMembership {
}
msg = "class TestNestmateMembership$CallerNoHost tried to access " +
"private method TestNestmateMembership$Target.m()V";
"private method 'void TestNestmateMembership$Target.m()'";
try {
CallerNoHost.invokeTarget();
throw new Error("Missing IllegalAccessError: " + msg);
@ -707,7 +707,7 @@ public class TestNestmateMembership {
check_expected(expected, msg);
}
msg = "class TestNestmateMembership$CallerNoHost tried to access private " +
"method TestNestmateMembership$TargetNoHost.m()V";
"method 'void TestNestmateMembership$TargetNoHost.m()'";
try {
CallerNoHost.invokeTargetNoHost();
throw new Error("Missing IllegalAccessError: " + msg);
@ -950,7 +950,7 @@ public class TestNestmateMembership {
static void test_NoHostConstruct() throws Throwable {
System.out.println("Testing for missing nest-host attribute");
String msg = "class TestNestmateMembership$Caller tried to access private " +
"method TestNestmateMembership$TargetNoHost.<init>()V";
"method 'void TestNestmateMembership$TargetNoHost.<init>()'";
try {
Caller.newTargetNoHost();
throw new Error("Missing IncompatibleClassChangeError: " + msg);
@ -977,7 +977,7 @@ public class TestNestmateMembership {
}
msg = "class TestNestmateMembership$CallerNoHost tried to access private " +
"method TestNestmateMembership$Target.<init>()V";
"method 'void TestNestmateMembership$Target.<init>()'";
try {
CallerNoHost.newTarget();
throw new Error("Missing IncompatibleClassChangeError: " + msg);
@ -986,7 +986,7 @@ public class TestNestmateMembership {
check_expected(expected, msg);
}
msg = "class TestNestmateMembership$CallerNoHost tried to access private " +
"method TestNestmateMembership$TargetNoHost.<init>()V";
"method 'void TestNestmateMembership$TargetNoHost.<init>()'";
try {
CallerNoHost.newTargetNoHost();
throw new Error("Missing IncompatibleClassChangeError: " + msg);

View file

@ -51,7 +51,7 @@ public class TestConstructorHierarchy {
throw new Error("Unexpected construction of ExternalSuper");
}
catch (IllegalAccessError iae) {
if (iae.getMessage().contains("class TestConstructorHierarchy tried to access private method ExternalSuper.<init>()V")) {
if (iae.getMessage().contains("class TestConstructorHierarchy tried to access private method 'void ExternalSuper.<init>()'")) {
System.out.println("Got expected exception constructing ExternalSuper: " + iae);
}
else throw new Error("Unexpected IllegalAccessError: " + iae);
@ -61,7 +61,7 @@ public class TestConstructorHierarchy {
throw new Error("Unexpected construction of NestedA and supers");
}
catch (IllegalAccessError iae) {
if (iae.getMessage().contains("class TestConstructorHierarchy$NestedA tried to access private method ExternalSuper.<init>()V")) {
if (iae.getMessage().contains("class TestConstructorHierarchy$NestedA tried to access private method 'void ExternalSuper.<init>()'")) {
System.out.println("Got expected exception constructing NestedA: " + iae);
}
else throw new Error("Unexpected IllegalAccessError: " + iae);
@ -71,7 +71,7 @@ public class TestConstructorHierarchy {
throw new Error("Unexpected construction of ExternalSub");
}
catch (IllegalAccessError iae) {
if (iae.getMessage().contains("class ExternalSub tried to access private method TestConstructorHierarchy$NestedA.<init>()V")) {
if (iae.getMessage().contains("class ExternalSub tried to access private method 'void TestConstructorHierarchy$NestedA.<init>()'")) {
System.out.println("Got expected exception constructing ExternalSub: " + iae);
}
else throw new Error("Unexpected IllegalAccessError: " + iae);

View file

@ -99,11 +99,11 @@ public class AbstractMethodErrorTest {
}
private static String expectedErrorMessageAME1_1 =
"Missing implementation of resolved method abstract " +
"anAbstractMethod()Ljava/lang/String; of abstract class AME1_B.";
"Missing implementation of resolved method 'abstract " +
"java.lang.String anAbstractMethod()' of abstract class AME1_B.";
private static String expectedErrorMessageAME1_2 =
"Receiver class AME1_E does not define or inherit an implementation of the " +
"resolved method abstract aFunctionOfMyInterface()Ljava/lang/String; of " +
"resolved method 'abstract java.lang.String aFunctionOfMyInterface()' of " +
"interface AME1_C.";
public static void test_ame1() {
@ -158,11 +158,11 @@ public class AbstractMethodErrorTest {
}
private static String expectedErrorMessageAME2_Interpreted =
"Missing implementation of resolved method abstract " +
"aFunctionOfMyInterface()V of interface AME2_A.";
"Missing implementation of resolved method 'abstract " +
"void aFunctionOfMyInterface()' of interface AME2_A.";
private static String expectedErrorMessageAME2_Compiled =
"Receiver class AME2_C does not define or inherit an implementation of the resolved method " +
"abstract aFunctionOfMyInterface()V of interface AME2_A.";
"'abstract void aFunctionOfMyInterface()' of interface AME2_A.";
public AbstractMethodErrorTest() throws InstantiationException, IllegalAccessException {
try {
@ -228,7 +228,7 @@ public class AbstractMethodErrorTest {
private static String expectedErrorMessageAME3_1 =
"Receiver class AME3_C does not define or inherit an implementation of the resolved method " +
"ma()V of class AME3_A. Selected method is abstract AME3_B.ma()V.";
"'void ma()' of class AME3_A. Selected method is 'abstract void AME3_B.ma()'.";
// Testing abstract class that extends a class that has an implementation.
// Loop so that method gets eventually compiled/osred.
@ -259,7 +259,7 @@ public class AbstractMethodErrorTest {
private static String expectedErrorMessageAME3_2 =
"Receiver class AME3_C does not define or inherit an implementation of " +
"the resolved method abstract ma()V of abstract class AME3_B.";
"the resolved method 'abstract void ma()' of abstract class AME3_B.";
// Testing abstract class that extends a class that has an implementation.
// Loop so that method gets eventually compiled/osred.
@ -289,7 +289,7 @@ public class AbstractMethodErrorTest {
}
private static String expectedErrorMessageAME4 =
"Missing implementation of resolved method abstract ma()V of " +
"Missing implementation of resolved method 'abstract void ma()' of " +
"abstract class AME4_B.";
// Testing abstract class that extends a class that has an implementation.
@ -336,7 +336,7 @@ public class AbstractMethodErrorTest {
}
private static String expectedErrorMessageAME5_VtableStub =
"Receiver class AME5_B does not define or inherit an implementation of the resolved method abstract mc()V " +
"Receiver class AME5_B does not define or inherit an implementation of the resolved method 'abstract void mc()' " +
"of abstract class AME5_A.";
// AbstractMethodErrors detected in vtable stubs.
@ -409,7 +409,7 @@ public class AbstractMethodErrorTest {
private static String expectedErrorMessageAME6_ItableStub =
"Receiver class AME6_B does not define or inherit an implementation of the resolved" +
" method abstract mc()V of interface AME6_A.";
" method 'abstract void mc()' of interface AME6_A.";
// -------------------------------------------------------------------------
// AbstractMethodErrors detected in itable stubs.

View file

@ -141,7 +141,7 @@ abstract public class IllegalAccessErrorTest {
private static void iae4_m() { }
private static String expectedErrorMessage4 =
"class test.Runner4 tried to access private method test.IllegalAccessErrorTest.iae4_m()V " +
"class test.Runner4 tried to access private method 'void test.IllegalAccessErrorTest.iae4_m()' " +
"(test.Runner4 and test.IllegalAccessErrorTest are in unnamed module of loader 'app')";
// Test according to java/lang/invoke/DefineClassTest.java
@ -264,7 +264,7 @@ abstract public class IllegalAccessErrorTest {
}
private static String expectedErrorMessage7_1 =
"class test.IAE78_B tried to access method test.IAE78_A.<init>()V " +
"class test.IAE78_B tried to access method 'void test.IAE78_A.<init>()' " +
"(test.IAE78_B is in unnamed module of loader 'test7_method_CL' @";
private static String expectedErrorMessage7_2 =
"; test.IAE78_A is in unnamed module of loader 'app')";

View file

@ -0,0 +1,37 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019 SAP SE. 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package test;
/* Method ma() is missing in this implementation to cause error. */
class TeMe3_C extends TeMe3_B {
public Method "<init>":"()V"
stack 1 locals 1
{
aload_0;
invokespecial Method TeMe3_B."<init>":()V;
return;
}
}

View file

@ -0,0 +1,151 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019 SAP SE. 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @summary Check that methods are printed properly.
* @compile -encoding UTF-8 TestPrintingMethods.java
* @compile TeMe3_C.jasm
* @run main/othervm -Xbootclasspath/a:. test.TestPrintingMethods
*/
package test;
public class TestPrintingMethods {
private static String expectedErrorMessage_VV = "void test.TeMe3_B.ma()";
private static String expectedErrorMessage_integral = "double[][] test.TeMe3_B.ma(int, boolean, byte[][], float)";
private static String expectedErrorMessage_classes = "test.TeMe3_B[][] test.TeMe3_B.ma(java.lang.Object[][][])";
private static String expectedErrorMessage_unicode = "java.lang.Object test.TeMe3_B.m\u20ac\u00a3a(java.lang.Object)";
static void checkMsg(Error e, String expected) throws Exception {
String errorMsg = e.getMessage();
if (errorMsg == null) {
throw new RuntimeException("Caught AbstractMethodError with empty message.");
} else if (errorMsg.contains(expected)) {
System.out.println("Passed with message: " + errorMsg);
} else {
System.out.println("Expected method to be printed as \"" + expected + "\"\n" +
"in exception message: " + errorMsg);
throw new RuntimeException("Method not printed as expected.");
}
}
// Call various missing methods to check that the exception
// message contains the proper string for the method name and
// signature. We expect Java-like printing of parameters etc.
static void test() throws Exception {
TeMe3_A c = new TeMe3_C();
try {
c.ma();
throw new RuntimeException("Expected AbstractMethodError was not thrown.");
} catch (AbstractMethodError e) {
checkMsg(e, expectedErrorMessage_VV);
}
try {
c.ma(2, true, new byte[2][3], 23.4f);
throw new RuntimeException("Expected AbstractMethodError was not thrown.");
} catch (AbstractMethodError e) {
checkMsg(e, expectedErrorMessage_integral);
}
try {
c.ma(new java.lang.Object[1][2][3]);
throw new RuntimeException("Expected AbstractMethodError was not thrown.");
} catch (AbstractMethodError e) {
checkMsg(e, expectedErrorMessage_classes);
}
try {
c.m\u20ac\u00a3a(new java.lang.Object());
throw new RuntimeException("Expected AbstractMethodError was not thrown.");
} catch (AbstractMethodError e) {
checkMsg(e, expectedErrorMessage_unicode);
}
}
public static void main(String[] args) throws Exception {
test();
}
}
// Helper classes to test abstract method error.
//
// Errorneous versions of these classes are implemented in java
// assembler.
// -----------------------------------------------------------------------
// Test AbstractMethod error shadowing existing implementation.
//
// Class hierachy:
//
// A // A class implementing m() and similar.
// |
// B // An abstract class defining m() abstract.
// |
// C // An errorneous class lacking an implementation of m().
//
class TeMe3_A {
public void ma() {
System.out.print("A.ma()");
}
public double[][] ma(int i, boolean z, byte[][] b, float f) {
return null;
}
public TeMe3_B[][] ma(java.lang.Object[][][] o) {
return null;
}
public java.lang.Object m\u20ac\u00a3a(java.lang.Object s) {
return null;
}
}
abstract class TeMe3_B extends TeMe3_A {
public abstract void ma();
public abstract double[][] ma(int i, boolean z, byte[][] b, float f);
public abstract TeMe3_B[][] ma(java.lang.Object[][][] o);
public abstract java.lang.Object m\u20ac\u00a3a(java.lang.Object s);
}
// An errorneous version of this class is implemented in java
// assembler.
class TeMe3_C extends TeMe3_B {
// These methods are missing in the .jasm implementation.
public void ma() {
System.out.print("C.ma()");
}
public double[][] ma(int i, boolean z, byte[][] b, float f) {
return new double[2][2];
}
public TeMe3_B[][] ma(java.lang.Object[][][] o) {
return new TeMe3_C[3][3];
}
public java.lang.Object m\u20ac\u00a3a(java.lang.Object s) {
return new java.lang.Object();
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2019, 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
@ -103,7 +103,7 @@ public class ExpQualToM1PrivateMethodIAE {
// java.lang.IllegalAccessError:
// tried to access private method p2.c2.method2()V from class p1.c1 (p2.c2 is in module m2x of loader
// myloaders.MySameClassLoader @<id>; p1.c1 is in module m1x of loader myloaders.MySameClassLoader @<id>)
if (!message.contains("class p1.c1 tried to access private method p2.c2.method2()V " +
if (!message.contains("class p1.c1 tried to access private method 'void p2.c2.method2()' " +
"(p1.c1 is in module m1x of loader myloaders.MySameClassLoader @") ||
!message.contains("; p2.c2 is in module m2x of loader myloaders.MySameClassLoader @")) {
throw new RuntimeException("Test Failed, an IAE was thrown with the wrong message: " + e.toString());