< prev index next >

src/share/vm/oops/constantPool.cpp

Print this page
rev 11945 : 8023697: failed class resolution reports different class name in detail message for the first and subsequent times
Summary: Cache detail message when we cache exception for constant pool resolution.
Reviewed-by: acorn, twisti, jrose
rev 11949 : 8048933: -XX:+TraceExceptions output should include the message
Summary: Add the exception detail message to the tracing output
Reviewed-by: minqi, dholmes
rev 11952 : Merge jdk8u272-b02

@@ -233,18 +233,18 @@
     }
   } // unlocking constantPool
 
 
   // The original attempt to resolve this constant pool entry failed so find the
-  // original error and throw it again (JVMS 5.4.3).
+  // class of the original error and throw another error of the same class (JVMS 5.4.3).
+  // If there is a detail message, pass that detail message to the error constructor.
+  // The JVMS does not strictly require us to duplicate the same detail message,
+  // or any internal exception fields such as cause or stacktrace.  But since the
+  // detail message is often a class name or other literal string, we will repeat it if
+  // we can find it in the symbol table.
   if (in_error) {
-    Symbol* error = SystemDictionary::find_resolution_error(this_oop, which);
-    guarantee(error != (Symbol*)NULL, "tag mismatch with resolution error table");
-    ResourceMark rm;
-    // exception text will be the class name
-    const char* className = this_oop->unresolved_klass_at(which)->as_C_string();
-    THROW_MSG_0(error, className);
+    throw_resolution_error(this_oop, which, CHECK_0);
   }
 
   if (do_resolve) {
     // this_oop must be unlocked during resolve_or_fail
     oop protection_domain = this_oop->pool_holder()->protection_domain();

@@ -260,50 +260,22 @@
     }
 
     // Failed to resolve class. We must record the errors so that subsequent attempts
     // to resolve this constant pool entry fail with the same error (JVMS 5.4.3).
     if (HAS_PENDING_EXCEPTION) {
-      ResourceMark rm;
-      Symbol* error = PENDING_EXCEPTION->klass()->name();
-
-      bool throw_orig_error = false;
-      {
         MonitorLockerEx ml(this_oop->lock());
 
         // some other thread has beaten us and has resolved the class.
         if (this_oop->tag_at(which).is_klass()) {
           CLEAR_PENDING_EXCEPTION;
           entry = this_oop->resolved_klass_at(which);
           return entry.get_klass();
         }
 
-        if (!PENDING_EXCEPTION->
-              is_a(SystemDictionary::LinkageError_klass())) {
-          // Just throw the exception and don't prevent these classes from
-          // being loaded due to virtual machine errors like StackOverflow
-          // and OutOfMemoryError, etc, or if the thread was hit by stop()
-          // Needs clarification to section 5.4.3 of the VM spec (see 6308271)
-        }
-        else if (!this_oop->tag_at(which).is_unresolved_klass_in_error()) {
-          SystemDictionary::add_resolution_error(this_oop, which, error);
-          this_oop->tag_at_put(which, JVM_CONSTANT_UnresolvedClassInError);
-        } else {
-          // some other thread has put the class in error state.
-          error = SystemDictionary::find_resolution_error(this_oop, which);
-          assert(error != NULL, "checking");
-          throw_orig_error = true;
-        }
-      } // unlocked
-
-      if (throw_orig_error) {
-        CLEAR_PENDING_EXCEPTION;
-        ResourceMark rm;
-        const char* className = this_oop->unresolved_klass_at(which)->as_C_string();
-        THROW_MSG_0(error, className);
-      }
-
-      return 0;
+        // The tag could have changed to in-error before the lock but we have to
+        // handle that here for the class case.
+        save_and_throw_exception(this_oop, which, constantTag(JVM_CONSTANT_UnresolvedClass), CHECK_0);
     }
 
     if (TraceClassResolution && !k()->oop_is_array()) {
       // skip resolving the constant pool so that this code get's
       // called the next time some bytecodes refer to this class.

@@ -595,41 +567,77 @@
   }
   // set_preresolution(); or some bit for future use
   return true;
 }
 
-// If resolution for MethodHandle or MethodType fails, save the exception
+Symbol* ConstantPool::exception_message(constantPoolHandle this_oop, int which, constantTag tag, oop pending_exception) {
+  // Dig out the detailed message to reuse if possible
+  Symbol* message = java_lang_Throwable::detail_message(pending_exception);
+  if (message != NULL) {
+    return message;
+  }
+
+  // Return specific message for the tag
+  switch (tag.value()) {
+  case JVM_CONSTANT_UnresolvedClass:
+    // return the class name in the error message
+    message = this_oop->unresolved_klass_at(which);
+    break;
+  case JVM_CONSTANT_MethodHandle:
+    // return the method handle name in the error message
+    message = this_oop->method_handle_name_ref_at(which);
+    break;
+  case JVM_CONSTANT_MethodType:
+    // return the method type signature in the error message
+    message = this_oop->method_type_signature_at(which);
+    break;
+  default:
+    ShouldNotReachHere();
+  }
+
+  return message;
+}
+
+void ConstantPool::throw_resolution_error(constantPoolHandle this_oop, int which, TRAPS) {
+  Symbol* message = NULL;
+  Symbol* error = SystemDictionary::find_resolution_error(this_oop, which, &message);
+  assert(error != NULL && message != NULL, "checking");
+  CLEAR_PENDING_EXCEPTION;
+  ResourceMark rm;
+  THROW_MSG(error, message->as_C_string());
+}
+
+// If resolution for Class, MethodHandle or MethodType fails, save the exception
 // in the resolution error table, so that the same exception is thrown again.
 void ConstantPool::save_and_throw_exception(constantPoolHandle this_oop, int which,
-                                     int tag, TRAPS) {
-  ResourceMark rm;
+                                            constantTag tag, TRAPS) {
+  assert(this_oop->lock()->is_locked(), "constant pool lock should be held");
   Symbol* error = PENDING_EXCEPTION->klass()->name();
-  MonitorLockerEx ml(this_oop->lock());  // lock cpool to change tag.
 
-  int error_tag = (tag == JVM_CONSTANT_MethodHandle) ?
-           JVM_CONSTANT_MethodHandleInError : JVM_CONSTANT_MethodTypeInError;
+  int error_tag = tag.error_value();
 
   if (!PENDING_EXCEPTION->
     is_a(SystemDictionary::LinkageError_klass())) {
     // Just throw the exception and don't prevent these classes from
     // being loaded due to virtual machine errors like StackOverflow
     // and OutOfMemoryError, etc, or if the thread was hit by stop()
     // Needs clarification to section 5.4.3 of the VM spec (see 6308271)
-
   } else if (this_oop->tag_at(which).value() != error_tag) {
-    SystemDictionary::add_resolution_error(this_oop, which, error);
+    Symbol* message = exception_message(this_oop, which, tag, PENDING_EXCEPTION);
+    SystemDictionary::add_resolution_error(this_oop, which, error, message);
     this_oop->tag_at_put(which, error_tag);
   } else {
-    // some other thread has put the class in error state.
-    error = SystemDictionary::find_resolution_error(this_oop, which);
-    assert(error != NULL, "checking");
-    CLEAR_PENDING_EXCEPTION;
-    THROW_MSG(error, "");
+    // some other thread put this in error state
+    throw_resolution_error(this_oop, which, CHECK);
   }
+
+  // This exits with some pending exception
+  assert(HAS_PENDING_EXCEPTION, "should not be cleared");
 }
 
 
+
 // Called to resolve constants in the constant pool and return an oop.
 // Some constant pool entries cache their resolved oop. This is also
 // called to create oops from constants to use in arguments for invokedynamic
 oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_oop, int index, int cache_index, TRAPS) {
   oop result_oop = NULL;

@@ -653,13 +661,13 @@
     index = this_oop->object_to_cp_index(cache_index);
   }
 
   jvalue prim_value;  // temp used only in a few cases below
 
-  int tag_value = this_oop->tag_at(index).value();
+  constantTag tag = this_oop->tag_at(index);
 
-  switch (tag_value) {
+  switch (tag.value()) {
 
   case JVM_CONSTANT_UnresolvedClass:
   case JVM_CONSTANT_UnresolvedClassInError:
   case JVM_CONSTANT_Class:
     {

@@ -680,14 +688,11 @@
     break;
 
   case JVM_CONSTANT_MethodHandleInError:
   case JVM_CONSTANT_MethodTypeInError:
     {
-      Symbol* error = SystemDictionary::find_resolution_error(this_oop, index);
-      guarantee(error != (Symbol*)NULL, "tag mismatch with resolution error table");
-      ResourceMark rm;
-      THROW_MSG_0(error, "");
+      throw_resolution_error(this_oop, index, CHECK_NULL);
       break;
     }
 
   case JVM_CONSTANT_MethodHandle:
     {

@@ -707,11 +712,12 @@
       Handle value = SystemDictionary::link_method_handle_constant(klass, ref_kind,
                                                                    callee, name, signature,
                                                                    THREAD);
       result_oop = value();
       if (HAS_PENDING_EXCEPTION) {
-        save_and_throw_exception(this_oop, index, tag_value, CHECK_NULL);
+        MonitorLockerEx ml(this_oop->lock());  // lock cpool to change tag.
+        save_and_throw_exception(this_oop, index, tag, CHECK_NULL);
       }
       break;
     }
 
   case JVM_CONSTANT_MethodType:

@@ -723,11 +729,12 @@
                       signature->as_C_string());
       KlassHandle klass(THREAD, this_oop->pool_holder());
       Handle value = SystemDictionary::find_method_handle_type(signature, klass, THREAD);
       result_oop = value();
       if (HAS_PENDING_EXCEPTION) {
-        save_and_throw_exception(this_oop, index, tag_value, CHECK_NULL);
+        MonitorLockerEx ml(this_oop->lock());  // lock cpool to change tag.
+        save_and_throw_exception(this_oop, index, tag, CHECK_NULL);
       }
       break;
     }
 
   case JVM_CONSTANT_Integer:

@@ -754,11 +761,11 @@
     result_oop = java_lang_boxing_object::create(T_DOUBLE, &prim_value, CHECK_NULL);
     break;
 
   default:
     DEBUG_ONLY( tty->print_cr("*** %p: tag at CP[%d/%d] = %d",
-                              this_oop(), index, cache_index, tag_value) );
+                              this_oop(), index, cache_index, tag.value()));
     assert(false, "unexpected constant tag");
     break;
   }
 
   if (cache_index >= 0) {
< prev index next >