提交 e7deac10 编写于 作者: C coleenp

8023697: failed class resolution reports different class name in detail...

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
上级 86f2f2ba
/*
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2014, 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
......@@ -32,12 +32,13 @@
// add new entry to the table
void ResolutionErrorTable::add_entry(int index, unsigned int hash,
constantPoolHandle pool, int cp_index, Symbol* error)
constantPoolHandle pool, int cp_index,
Symbol* error, Symbol* message)
{
assert_locked_or_safepoint(SystemDictionary_lock);
assert(!pool.is_null() && error != NULL, "adding NULL obj");
ResolutionErrorEntry* entry = new_entry(hash, pool(), cp_index, error);
ResolutionErrorEntry* entry = new_entry(hash, pool(), cp_index, error, message);
add_entry(index, entry);
}
......@@ -58,19 +59,26 @@ ResolutionErrorEntry* ResolutionErrorTable::find_entry(int index, unsigned int h
}
void ResolutionErrorEntry::set_error(Symbol* e) {
assert(e == NULL || _error == NULL, "cannot reset error");
assert(e != NULL, "must set a value");
_error = e;
if (_error != NULL) _error->increment_refcount();
_error->increment_refcount();
}
void ResolutionErrorEntry::set_message(Symbol* c) {
assert(c != NULL, "must set a value");
_message = c;
_message->increment_refcount();
}
// create new error entry
ResolutionErrorEntry* ResolutionErrorTable::new_entry(int hash, ConstantPool* pool,
int cp_index, Symbol* error)
int cp_index, Symbol* error,
Symbol* message)
{
ResolutionErrorEntry* entry = (ResolutionErrorEntry*)Hashtable<ConstantPool*, mtClass>::new_entry(hash, pool);
entry->set_cp_index(cp_index);
NOT_PRODUCT(entry->set_error(NULL);)
entry->set_error(error);
entry->set_message(message);
return entry;
}
......@@ -79,6 +87,7 @@ void ResolutionErrorTable::free_entry(ResolutionErrorEntry *entry) {
// decrement error refcount
assert(entry->error() != NULL, "error should be set");
entry->error()->decrement_refcount();
entry->message()->decrement_refcount();
Hashtable<ConstantPool*, mtClass>::free_entry(entry);
}
......
/*
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2014, 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
......@@ -38,7 +38,8 @@ class ResolutionErrorTable : public Hashtable<ConstantPool*, mtClass> {
public:
ResolutionErrorTable(int table_size);
ResolutionErrorEntry* new_entry(int hash, ConstantPool* pool, int cp_index, Symbol* error);
ResolutionErrorEntry* new_entry(int hash, ConstantPool* pool, int cp_index,
Symbol* error, Symbol* message);
void free_entry(ResolutionErrorEntry *entry);
ResolutionErrorEntry* bucket(int i) {
......@@ -55,7 +56,7 @@ public:
}
void add_entry(int index, unsigned int hash,
constantPoolHandle pool, int which, Symbol* error);
constantPoolHandle pool, int which, Symbol* error, Symbol* message);
// find error given the constant pool and constant pool index
......@@ -79,10 +80,10 @@ class ResolutionErrorEntry : public HashtableEntry<ConstantPool*, mtClass> {
private:
int _cp_index;
Symbol* _error;
Symbol* _message;
public:
ConstantPool* pool() const { return (ConstantPool*)literal(); }
ConstantPool** pool_addr() { return (ConstantPool**)literal_addr(); }
ConstantPool* pool() const { return literal(); }
int cp_index() const { return _cp_index; }
void set_cp_index(int cp_index) { _cp_index = cp_index; }
......@@ -90,6 +91,9 @@ class ResolutionErrorEntry : public HashtableEntry<ConstantPool*, mtClass> {
Symbol* error() const { return _error; }
void set_error(Symbol* e);
Symbol* message() const { return _message; }
void set_message(Symbol* c);
ResolutionErrorEntry* next() const {
return (ResolutionErrorEntry*)HashtableEntry<ConstantPool*, mtClass>::next();
}
......
......@@ -172,12 +172,14 @@ Klass* SystemDictionary::resolve_or_fail(Symbol* class_name, Handle class_loader
if (HAS_PENDING_EXCEPTION || klass == NULL) {
KlassHandle k_h(THREAD, klass);
// can return a null klass
klass = handle_resolution_exception(class_name, class_loader, protection_domain, throw_error, k_h, THREAD);
klass = handle_resolution_exception(class_name, throw_error, k_h, THREAD);
}
return klass;
}
Klass* SystemDictionary::handle_resolution_exception(Symbol* class_name, Handle class_loader, Handle protection_domain, bool throw_error, KlassHandle klass_h, TRAPS) {
Klass* SystemDictionary::handle_resolution_exception(Symbol* class_name,
bool throw_error,
KlassHandle klass_h, TRAPS) {
if (HAS_PENDING_EXCEPTION) {
// If we have a pending exception we forward it to the caller, unless throw_error is true,
// in which case we have to check whether the pending exception is a ClassNotFoundException,
......@@ -385,7 +387,7 @@ Klass* SystemDictionary::resolve_super_or_fail(Symbol* child_name,
}
if (HAS_PENDING_EXCEPTION || superk_h() == NULL) {
// can null superk
superk_h = KlassHandle(THREAD, handle_resolution_exception(class_name, class_loader, protection_domain, true, superk_h, THREAD));
superk_h = KlassHandle(THREAD, handle_resolution_exception(class_name, true, superk_h, THREAD));
}
return superk_h();
......@@ -2119,12 +2121,13 @@ bool SystemDictionary::add_loader_constraint(Symbol* class_name,
// Add entry to resolution error table to record the error when the first
// attempt to resolve a reference to a class has failed.
void SystemDictionary::add_resolution_error(constantPoolHandle pool, int which, Symbol* error) {
void SystemDictionary::add_resolution_error(constantPoolHandle pool, int which,
Symbol* error, Symbol* message) {
unsigned int hash = resolution_errors()->compute_hash(pool, which);
int index = resolution_errors()->hash_to_index(hash);
{
MutexLocker ml(SystemDictionary_lock, Thread::current());
resolution_errors()->add_entry(index, hash, pool, which, error);
resolution_errors()->add_entry(index, hash, pool, which, error, message);
}
}
......@@ -2134,13 +2137,19 @@ void SystemDictionary::delete_resolution_error(ConstantPool* pool) {
}
// Lookup resolution error table. Returns error if found, otherwise NULL.
Symbol* SystemDictionary::find_resolution_error(constantPoolHandle pool, int which) {
Symbol* SystemDictionary::find_resolution_error(constantPoolHandle pool, int which,
Symbol** message) {
unsigned int hash = resolution_errors()->compute_hash(pool, which);
int index = resolution_errors()->hash_to_index(hash);
{
MutexLocker ml(SystemDictionary_lock, Thread::current());
ResolutionErrorEntry* entry = resolution_errors()->find_entry(index, hash, pool, which);
return (entry != NULL) ? entry->error() : (Symbol*)NULL;
if (entry != NULL) {
*message = entry->message();
return entry->error();
} else {
return NULL;
}
}
}
......
......@@ -228,7 +228,7 @@ class SystemDictionary : AllStatic {
static Klass* resolve_or_fail(Symbol* class_name, bool throw_error, TRAPS);
private:
// handle error translation for resolve_or_null results
static Klass* handle_resolution_exception(Symbol* class_name, Handle class_loader, Handle protection_domain, bool throw_error, KlassHandle klass_h, TRAPS);
static Klass* handle_resolution_exception(Symbol* class_name, bool throw_error, KlassHandle klass_h, TRAPS);
public:
......@@ -531,9 +531,11 @@ public:
// Record the error when the first attempt to resolve a reference from a constant
// pool entry to a class fails.
static void add_resolution_error(constantPoolHandle pool, int which, Symbol* error);
static void add_resolution_error(constantPoolHandle pool, int which, Symbol* error,
Symbol* message);
static void delete_resolution_error(ConstantPool* pool);
static Symbol* find_resolution_error(constantPoolHandle pool, int which);
static Symbol* find_resolution_error(constantPoolHandle pool, int which,
Symbol** message);
private:
......
......@@ -223,14 +223,14 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_cp, int which, TRAPS)
// 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_cp, which);
guarantee(error != (Symbol*)NULL, "tag mismatch with resolution error table");
ResourceMark rm;
// exception text will be the class name
const char* className = this_cp->unresolved_klass_at(which)->as_C_string();
THROW_MSG_0(error, className);
throw_resolution_error(this_cp, which, CHECK_0);
}
if (do_resolve) {
......@@ -250,11 +250,6 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_cp, int which, TRAPS)
// 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_cp->lock());
// some other thread has beaten us and has resolved the class.
......@@ -264,32 +259,9 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_cp, int which, TRAPS)
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_cp->tag_at(which).is_unresolved_klass_in_error()) {
SystemDictionary::add_resolution_error(this_cp, which, error);
this_cp->tag_at_put(which, JVM_CONSTANT_UnresolvedClassInError);
} else {
// some other thread has put the class in error state.
error = SystemDictionary::find_resolution_error(this_cp, which);
assert(error != NULL, "checking");
throw_orig_error = true;
}
} // unlocked
if (throw_orig_error) {
CLEAR_PENDING_EXCEPTION;
ResourceMark rm;
const char* className = this_cp->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_cp, which, constantTag(JVM_CONSTANT_UnresolvedClass), CHECK_0);
}
if (TraceClassResolution && !k()->oop_is_array()) {
......@@ -587,16 +559,55 @@ bool ConstantPool::resolve_class_constants(TRAPS) {
return true;
}
// If resolution for MethodHandle or MethodType fails, save the exception
Symbol* ConstantPool::exception_message(constantPoolHandle this_cp, int which, constantTag tag, oop pending_exception) {
// Dig out the detailed message to reuse if possible
Symbol* message = NULL;
oop detailed_message = java_lang_Throwable::message(pending_exception);
if (detailed_message != NULL) {
message = java_lang_String::as_symbol_or_null(detailed_message);
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_cp->unresolved_klass_at(which);
break;
case JVM_CONSTANT_MethodHandle:
// return the method handle name in the error message
message = this_cp->method_handle_name_ref_at(which);
break;
case JVM_CONSTANT_MethodType:
// return the method type signature in the error message
message = this_cp->method_type_signature_at(which);
break;
default:
ShouldNotReachHere();
}
return message;
}
void ConstantPool::throw_resolution_error(constantPoolHandle this_cp, int which, TRAPS) {
Symbol* message = NULL;
Symbol* error = SystemDictionary::find_resolution_error(this_cp, 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_cp, int which,
int tag, TRAPS) {
ResourceMark rm;
constantTag tag, TRAPS) {
assert(this_cp->lock()->is_locked(), "constant pool lock should be held");
Symbol* error = PENDING_EXCEPTION->klass()->name();
MonitorLockerEx ml(this_cp->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())) {
......@@ -604,20 +615,21 @@ void ConstantPool::save_and_throw_exception(constantPoolHandle this_cp, int whic
// 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_cp->tag_at(which).value() != error_tag) {
SystemDictionary::add_resolution_error(this_cp, which, error);
Symbol* message = exception_message(this_cp, which, tag, PENDING_EXCEPTION);
SystemDictionary::add_resolution_error(this_cp, which, error, message);
this_cp->tag_at_put(which, error_tag);
} else {
// some other thread has put the class in error state.
error = SystemDictionary::find_resolution_error(this_cp, which);
assert(error != NULL, "checking");
CLEAR_PENDING_EXCEPTION;
THROW_MSG(error, "");
// some other thread put this in error state
throw_resolution_error(this_cp, 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
......@@ -645,9 +657,9 @@ oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_cp, int index
jvalue prim_value; // temp used only in a few cases below
int tag_value = this_cp->tag_at(index).value();
constantTag tag = this_cp->tag_at(index);
switch (tag_value) {
switch (tag.value()) {
case JVM_CONSTANT_UnresolvedClass:
case JVM_CONSTANT_UnresolvedClassInError:
......@@ -672,10 +684,7 @@ oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_cp, int index
case JVM_CONSTANT_MethodHandleInError:
case JVM_CONSTANT_MethodTypeInError:
{
Symbol* error = SystemDictionary::find_resolution_error(this_cp, index);
guarantee(error != (Symbol*)NULL, "tag mismatch with resolution error table");
ResourceMark rm;
THROW_MSG_0(error, "");
throw_resolution_error(this_cp, index, CHECK_NULL);
break;
}
......@@ -699,7 +708,8 @@ oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_cp, int index
THREAD);
result_oop = value();
if (HAS_PENDING_EXCEPTION) {
save_and_throw_exception(this_cp, index, tag_value, CHECK_NULL);
MonitorLockerEx ml(this_cp->lock()); // lock cpool to change tag.
save_and_throw_exception(this_cp, index, tag, CHECK_NULL);
}
break;
}
......@@ -715,7 +725,8 @@ oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_cp, int index
Handle value = SystemDictionary::find_method_handle_type(signature, klass, THREAD);
result_oop = value();
if (HAS_PENDING_EXCEPTION) {
save_and_throw_exception(this_cp, index, tag_value, CHECK_NULL);
MonitorLockerEx ml(this_cp->lock()); // lock cpool to change tag.
save_and_throw_exception(this_cp, index, tag, CHECK_NULL);
}
break;
}
......@@ -746,7 +757,7 @@ oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_cp, int index
default:
DEBUG_ONLY( tty->print_cr("*** %p: tag at CP[%d/%d] = %d",
this_cp(), index, cache_index, tag_value) );
this_cp(), index, cache_index, tag.value()));
assert(false, "unexpected constant tag");
break;
}
......
......@@ -823,9 +823,13 @@ class ConstantPool : public Metadata {
static void resolve_string_constants_impl(constantPoolHandle this_cp, TRAPS);
static oop resolve_constant_at_impl(constantPoolHandle this_cp, int index, int cache_index, TRAPS);
static void save_and_throw_exception(constantPoolHandle this_cp, int which, int tag_value, TRAPS);
static oop resolve_bootstrap_specifier_at_impl(constantPoolHandle this_cp, int index, TRAPS);
// Exception handling
static void throw_resolution_error(constantPoolHandle this_cp, int which, TRAPS);
static Symbol* exception_message(constantPoolHandle this_cp, int which, constantTag tag, oop pending_exception);
static void save_and_throw_exception(constantPoolHandle this_cp, int which, constantTag tag, TRAPS);
public:
// Merging ConstantPool* support:
bool compare_entry_to(int index1, constantPoolHandle cp2, int index2, TRAPS);
......
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2014, 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
......@@ -76,6 +76,20 @@ jbyte constantTag::non_error_value() const {
}
jbyte constantTag::error_value() const {
switch (_tag) {
case JVM_CONSTANT_UnresolvedClass:
return JVM_CONSTANT_UnresolvedClassInError;
case JVM_CONSTANT_MethodHandle:
return JVM_CONSTANT_MethodHandleInError;
case JVM_CONSTANT_MethodType:
return JVM_CONSTANT_MethodTypeInError;
default:
ShouldNotReachHere();
return JVM_CONSTANT_Invalid;
}
}
const char* constantTag::internal_name() const {
switch (_tag) {
case JVM_CONSTANT_Invalid :
......
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2014, 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
......@@ -109,6 +109,7 @@ class constantTag VALUE_OBJ_CLASS_SPEC {
}
jbyte value() const { return _tag; }
jbyte error_value() const;
jbyte non_error_value() const;
BasicType basic_type() const; // if used with ldc, what kind of value gets pushed?
......
/*
* Copyright (c) 2014, 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
* 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.
*/
// Class PropertySuper is not found.
public class Property extends PropertySuper {
}
/*
* Copyright (c) 2014, 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
* 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.
*/
// Class PropertySuper should be removed.
public class PropertySuper {
PropertySuper() { System.out.println("remove me for NoClassDefFoundError"); }
}
/*
* Copyright (c) 2014, 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
* 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 TestClassResolutionFail
* @bug 8023697
* @summary This tests that failed class resolution doesn't report different class name in detail message for the first and subsequent times
*/
import java.io.File;
public class TestClassResolutionFail {
static String message;
public static void test1() throws RuntimeException {
try {
Property p = new Property();
} catch (LinkageError e) {
message = e.getMessage();
}
try {
Property p = new Property();
} catch (LinkageError e) {
System.out.println(e.getMessage());
if (!e.getMessage().equals(message)) {
throw new RuntimeException("Wrong message: " + message + " != " + e.getMessage());
}
}
}
public static void main(java.lang.String[] unused) throws Exception {
// Remove PropertySuper class
String testClasses = System.getProperty("test.classes", ".");
File f = new File(testClasses + File.separator + "PropertySuper.class");
f.delete();
test1();
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册