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

Reviewed-by: dholmes, mdoerr, coleenp
diff --git a/src/hotspot/share/classfile/verifier.cpp b/src/hotspot/share/classfile/verifier.cpp
index 65f3a34..d2c18c8 100644
--- a/src/hotspot/share/classfile/verifier.cpp
+++ b/src/hotspot/share/classfile/verifier.cpp
@@ -1999,7 +1999,9 @@
   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();
 }
diff --git a/src/hotspot/share/interpreter/linkResolver.cpp b/src/hotspot/share/interpreter/linkResolver.cpp
index 92865ec..24ddca8 100644
--- a/src/hotspot/share/interpreter/linkResolver.cpp
+++ b/src/hotspot/share/interpreter/linkResolver.cpp
@@ -268,10 +268,6 @@
   _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;
@@ -600,14 +596,12 @@
     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()
@@ -677,12 +671,11 @@
     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(),
@@ -745,9 +738,11 @@
   // 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
@@ -770,11 +765,12 @@
   // 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.
@@ -846,9 +842,11 @@
   // 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
@@ -863,10 +861,11 @@
   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()) {
@@ -887,11 +886,12 @@
 
   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)) {
@@ -1092,11 +1092,11 @@
   // 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;
 }
@@ -1133,14 +1133,16 @@
   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;
   }
 
@@ -1159,27 +1161,23 @@
     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)) {
@@ -1228,10 +1226,11 @@
       // 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);
@@ -1253,8 +1252,8 @@
         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);
       }
     }
@@ -1263,20 +1262,21 @@
   // 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)) {
@@ -1314,23 +1314,22 @@
   // 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)) {
@@ -1479,10 +1478,11 @@
     // 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()) {
@@ -1821,19 +1821,22 @@
   }
 
   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());
diff --git a/src/hotspot/share/interpreter/linkResolver.hpp b/src/hotspot/share/interpreter/linkResolver.hpp
index 10937c8..e3fca2f 100644
--- a/src/hotspot/share/interpreter/linkResolver.hpp
+++ b/src/hotspot/share/interpreter/linkResolver.hpp
@@ -184,7 +184,6 @@
   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;
 };
diff --git a/src/hotspot/share/oops/constantPool.cpp b/src/hotspot/share/oops/constantPool.cpp
index 7e79f81..e531669 100644
--- a/src/hotspot/share/oops/constantPool.cpp
+++ b/src/hotspot/share/oops/constantPool.cpp
@@ -999,14 +999,17 @@
       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();
diff --git a/src/hotspot/share/oops/klassVtable.cpp b/src/hotspot/share/oops/klassVtable.cpp
index d34364e..d9d28eb 100644
--- a/src/hotspot/share/oops/klassVtable.cpp
+++ b/src/hotspot/share/oops/klassVtable.cpp
@@ -508,11 +508,11 @@
             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(),
@@ -1240,15 +1240,16 @@
           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),
diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp
index 22121df..4d1b4b2 100644
--- a/src/hotspot/share/oops/method.cpp
+++ b/src/hotspot/share/oops/method.cpp
@@ -176,6 +176,27 @@
   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
diff --git a/src/hotspot/share/oops/method.hpp b/src/hotspot/share/oops/method.hpp
index 922d0e9..f9ac6e2 100644
--- a/src/hotspot/share/oops/method.hpp
+++ b/src/hotspot/share/oops/method.hpp
@@ -179,8 +179,8 @@
   }
 
   // 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;
@@ -189,6 +189,18 @@
   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));
   }
diff --git a/src/hotspot/share/oops/symbol.cpp b/src/hotspot/share/oops/symbol.cpp
index 5655a68..50242d2 100644
--- a/src/hotspot/share/oops/symbol.cpp
+++ b/src/hotspot/share/oops/symbol.cpp
@@ -34,6 +34,7 @@
 #include "oops/symbol.hpp"
 #include "runtime/atomic.hpp"
 #include "runtime/os.hpp"
+#include "runtime/signature.hpp"
 
 Symbol::Symbol(const u1* name, int length, int refcount) {
   _refcount = refcount;
@@ -201,6 +202,66 @@
   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;
+  }
+}
+
 // Alternate hashing for unbalanced symbol tables.
 unsigned int Symbol::new_hash(juint seed) {
   ResourceMark rm;
diff --git a/src/hotspot/share/oops/symbol.hpp b/src/hotspot/share/oops/symbol.hpp
index f9fbd04..136fd9b 100644
--- a/src/hotspot/share/oops/symbol.hpp
+++ b/src/hotspot/share/oops/symbol.hpp
@@ -231,6 +231,15 @@
   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; }
 
diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp
index 67b8ff2..1601201 100644
--- a/src/hotspot/share/prims/jni.cpp
+++ b/src/hotspot/share/prims/jni.cpp
@@ -2971,8 +2971,9 @@
   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()) {
@@ -2981,8 +2982,9 @@
     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);
     }
   }
diff --git a/src/hotspot/share/prims/nativeLookup.cpp b/src/hotspot/share/prims/nativeLookup.cpp
index af660bf..00a4ce3 100644
--- a/src/hotspot/share/prims/nativeLookup.cpp
+++ b/src/hotspot/share/prims/nativeLookup.cpp
@@ -378,8 +378,11 @@
   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());
 }
 
 
diff --git a/src/hotspot/share/prims/stackwalk.cpp b/src/hotspot/share/prims/stackwalk.cpp
index 175e0a3..6c1e7ff 100644
--- a/src/hotspot/share/prims/stackwalk.cpp
+++ b/src/hotspot/share/prims/stackwalk.cpp
@@ -150,8 +150,8 @@
           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);
diff --git a/src/hotspot/share/runtime/reflection.cpp b/src/hotspot/share/runtime/reflection.cpp
index 60f0d38..9cb7154 100644
--- a/src/hotspot/share/runtime/reflection.cpp
+++ b/src/hotspot/share/runtime/reflection.cpp
@@ -1143,11 +1143,12 @@
           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(),
@@ -1162,10 +1163,13 @@
   // 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");
diff --git a/test/hotspot/jtreg/runtime/LoaderConstraints/itableLdrConstraint/Test.java b/test/hotspot/jtreg/runtime/LoaderConstraints/itableLdrConstraint/Test.java
index 807fec0..825d304 100644
--- a/test/hotspot/jtreg/runtime/LoaderConstraints/itableLdrConstraint/Test.java
+++ b/test/hotspot/jtreg/runtime/LoaderConstraints/itableLdrConstraint/Test.java
@@ -38,19 +38,19 @@
     // 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 @@
             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);
             }
diff --git a/test/hotspot/jtreg/runtime/LoaderConstraints/vtableLdrConstraint/Test.java b/test/hotspot/jtreg/runtime/LoaderConstraints/vtableLdrConstraint/Test.java
index 83acb4a..9c88739 100644
--- a/test/hotspot/jtreg/runtime/LoaderConstraints/vtableLdrConstraint/Test.java
+++ b/test/hotspot/jtreg/runtime/LoaderConstraints/vtableLdrConstraint/Test.java
@@ -38,7 +38,7 @@
     // 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 @@
     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 " +
diff --git a/test/hotspot/jtreg/runtime/Nestmates/membership/TestNestmateMembership.java b/test/hotspot/jtreg/runtime/Nestmates/membership/TestNestmateMembership.java
index 5ce9086..54ad86f 100644
--- a/test/hotspot/jtreg/runtime/Nestmates/membership/TestNestmateMembership.java
+++ b/test/hotspot/jtreg/runtime/Nestmates/membership/TestNestmateMembership.java
@@ -671,7 +671,7 @@
     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 @@
         }
 
         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 @@
             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 @@
     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 @@
         }
 
         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 @@
             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);
diff --git a/test/hotspot/jtreg/runtime/Nestmates/privateConstructors/TestConstructorHierarchy.java b/test/hotspot/jtreg/runtime/Nestmates/privateConstructors/TestConstructorHierarchy.java
index a19ac56..88ec0cc 100644
--- a/test/hotspot/jtreg/runtime/Nestmates/privateConstructors/TestConstructorHierarchy.java
+++ b/test/hotspot/jtreg/runtime/Nestmates/privateConstructors/TestConstructorHierarchy.java
@@ -51,7 +51,7 @@
             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 @@
             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 @@
             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);
diff --git a/test/hotspot/jtreg/runtime/exceptionMsgs/AbstractMethodError/AbstractMethodErrorTest.java b/test/hotspot/jtreg/runtime/exceptionMsgs/AbstractMethodError/AbstractMethodErrorTest.java
index 1dcf760..1da52dd 100644
--- a/test/hotspot/jtreg/runtime/exceptionMsgs/AbstractMethodError/AbstractMethodErrorTest.java
+++ b/test/hotspot/jtreg/runtime/exceptionMsgs/AbstractMethodError/AbstractMethodErrorTest.java
@@ -99,11 +99,11 @@
     }
 
     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 @@
     }
 
     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 @@
 
     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 @@
 
     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 @@
     }
 
     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 @@
     }
 
     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 @@
 
     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.
diff --git a/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IllegalAccessErrorTest.java b/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IllegalAccessErrorTest.java
index ff5a25b..0c3bc2d 100644
--- a/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IllegalAccessErrorTest.java
+++ b/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IllegalAccessErrorTest.java
@@ -141,7 +141,7 @@
     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 @@
     }
 
     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')";
diff --git a/test/hotspot/jtreg/runtime/exceptionMsgs/methodPrinting/TeMe3_C.jasm b/test/hotspot/jtreg/runtime/exceptionMsgs/methodPrinting/TeMe3_C.jasm
new file mode 100644
index 0000000..2085d43
--- /dev/null
+++ b/test/hotspot/jtreg/runtime/exceptionMsgs/methodPrinting/TeMe3_C.jasm
@@ -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;
+    }
+}
diff --git a/test/hotspot/jtreg/runtime/exceptionMsgs/methodPrinting/TestPrintingMethods.java b/test/hotspot/jtreg/runtime/exceptionMsgs/methodPrinting/TestPrintingMethods.java
new file mode 100644
index 0000000..5c413b0
--- /dev/null
+++ b/test/hotspot/jtreg/runtime/exceptionMsgs/methodPrinting/TestPrintingMethods.java
@@ -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();
+    }
+}
+
diff --git a/test/hotspot/jtreg/runtime/modules/AccessCheck/ExpQualToM1PrivateMethodIAE.java b/test/hotspot/jtreg/runtime/modules/AccessCheck/ExpQualToM1PrivateMethodIAE.java
index ac2ee32..0a6fcc6 100644
--- a/test/hotspot/jtreg/runtime/modules/AccessCheck/ExpQualToM1PrivateMethodIAE.java
+++ b/test/hotspot/jtreg/runtime/modules/AccessCheck/ExpQualToM1PrivateMethodIAE.java
@@ -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 @@
             // 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());