From 204bf2cdfec73890037af529d67d396d30662a44 Mon Sep 17 00:00:00 2001 From: Christian Thalinger Date: Wed, 26 Mar 2008 17:14:46 +0100 Subject: [PATCH] * src/cacaoh/dummy.c (resolve_handle_pending_exception): New function. * src/native/vm/sun/jvm.c (JVM_FindClassFromClassLoader): Added assert on throwError. (JVM_DoPrivileged): Throw PrivilegedActionException only if the exception is an instance of java.lang.Exception but not of java.lang.RuntimeException. * src/vm/exceptions.c (exceptions_new_class_utf): New function. (exceptions_throw_class_utf): Likewise. (exceptions_throw_classnotfoundexception): Use exceptions_throw_class_utf. (exceptions_classnotfoundexception_to_noclassdeffounderror): Removed. * src/vm/exceptions.h: Likewise. * src/vm/resolve.c (resolve_handle_pending_exception): New function. (resolve_class_from_name): Don't convert exception. * src/vm/resolve.h (resolve_handle_pending_exception): Added. * src/vmcore/class.c (class_java_lang_Exception): New global variable. (class_java_lang_ClassNotFoundException): Likewise. (class_java_lang_RuntimeException): Likewise. * src/vmcore/class.h: Likewise. * src/vmcore/linker.c (linker_init): Link new global classes. * src/vmcore/loader.c (loader_init): Load new global classes. * src/vmcore/utf8.c (utf_java_lang_RuntimeException): New global variable. (utf8_init): Initialize new global variable. * src/vmcore/utf8.h (utf_java_lang_RuntimeException): Export. * tests/regression/bugzilla/All.java: Added PR58. * tests/regression/bugzilla/PR58.java: New file. --- src/cacaoh/dummy.c | 5 + src/native/vm/sun/jvm.c | 22 ++- src/vm/exceptions.c | 268 ++++++++++++++-------------- src/vm/exceptions.h | 8 +- src/vm/resolve.c | 66 +++++-- src/vm/resolve.h | 9 +- src/vmcore/class.c | 8 +- src/vmcore/class.h | 8 +- src/vmcore/linker.c | 10 ++ src/vmcore/loader.c | 14 +- src/vmcore/utf8.c | 4 + src/vmcore/utf8.h | 1 + tests/regression/bugzilla/All.java | 1 + tests/regression/bugzilla/PR58.java | 59 ++++++ 14 files changed, 317 insertions(+), 166 deletions(-) create mode 100644 tests/regression/bugzilla/PR58.java diff --git a/src/cacaoh/dummy.c b/src/cacaoh/dummy.c index f7fe97c5f..3177b4143 100644 --- a/src/cacaoh/dummy.c +++ b/src/cacaoh/dummy.c @@ -608,6 +608,11 @@ char *properties_get(char *key) /* resolve ********************************************************************/ +void resolve_handle_pending_exception(bool throwError) +{ + vm_abort("resolve_handle_pending_exception: Not implemented."); +} + bool resolve_class_from_typedesc(typedesc *d, bool checkaccess, bool link, classinfo **result) { abort(); diff --git a/src/native/vm/sun/jvm.c b/src/native/vm/sun/jvm.c index 5c8d361d5..91545dd36 100644 --- a/src/native/vm/sun/jvm.c +++ b/src/native/vm/sun/jvm.c @@ -776,6 +776,11 @@ jclass JVM_FindClassFromClassLoader(JNIEnv* env, const char* name, jboolean init TRACEJVMCALLS(("JVM_FindClassFromClassLoader(name=%s, init=%d, loader=%p, throwError=%d)", name, init, loader, throwError)); + /* As of now, OpenJDK does not call this function with throwError + is true. */ + + assert(throwError == false); + u = utf_new_char(name); cl = loader_hashtable_classloader_add((java_handle_t *) loader); @@ -985,7 +990,7 @@ void JVM_SetProtectionDomain(JNIEnv *env, jclass cls, jobject protection_domain) jobject JVM_DoPrivileged(JNIEnv *env, jclass cls, jobject action, jobject context, jboolean wrapException) { - java_handle_t *o; + java_handle_t *h; classinfo *c; methodinfo *m; java_handle_t *result; @@ -993,8 +998,8 @@ jobject JVM_DoPrivileged(JNIEnv *env, jclass cls, jobject action, jobject contex TRACEJVMCALLS(("JVM_DoPrivileged(env=%p, cls=%p, action=%p, context=%p, wrapException=%d)", env, cls, action, context, wrapException)); - o = (java_handle_t *) action; - c = o->vftbl->class; + h = (java_handle_t *) action; + LLNI_class_get(h, c); if (action == NULL) { exceptions_throw_nullpointerexception(); @@ -1014,12 +1019,17 @@ jobject JVM_DoPrivileged(JNIEnv *env, jclass cls, jobject action, jobject contex /* XXX It seems something with a privileged stack needs to be done here. */ - result = vm_call_method(m, o); + result = vm_call_method(m, h); - e = exceptions_get_and_clear_exception(); + e = exceptions_get_exception(); if (e != NULL) { - exceptions_throw_privilegedactionexception(e); + if ( builtin_instanceof(e, class_java_lang_Exception) && + !builtin_instanceof(e, class_java_lang_RuntimeException)) { + exceptions_clear_exception(); + exceptions_throw_privilegedactionexception(e); + } + return NULL; } diff --git a/src/vm/exceptions.c b/src/vm/exceptions.c index 26ca1fda3..707328ec7 100644 --- a/src/vm/exceptions.c +++ b/src/vm/exceptions.c @@ -276,6 +276,44 @@ static void exceptions_abort(utf *classname, utf *message) } +/* exceptions_new_class_utf **************************************************** + + Creates an exception object with the given class and initalizes it + with the given utf message. + + IN: + c ......... exception class + message ... the message as an utf * + + RETURN VALUE: + an exception pointer (in any case -- either it is the newly + created exception, or an exception thrown while trying to create + it). + +*******************************************************************************/ + +static java_handle_t *exceptions_new_class_utf(classinfo *c, utf *message) +{ + java_handle_t *s; + java_handle_t *o; + + if (vm_initializing) + exceptions_abort(c->name, message); + + s = javastring_new(message); + + if (s == NULL) + return exceptions_get_exception(); + + o = native_new_and_init_string(c, s); + + if (o == NULL) + return exceptions_get_exception(); + + return o; +} + + /* exceptions_new_utf ********************************************************** Creates an exception object with the given name and initalizes it. @@ -307,6 +345,99 @@ static java_handle_t *exceptions_new_utf(utf *classname) } +/* exceptions_new_utf_javastring *********************************************** + + Creates an exception object with the given name and initalizes it + with the given java/lang/String message. + + IN: + classname....class name in UTF-8 + message......the message as a java.lang.String + + RETURN VALUE: + an exception pointer (in any case -- either it is the newly created + exception, or an exception thrown while trying to create it). + +*******************************************************************************/ + +static java_handle_t *exceptions_new_utf_javastring(utf *classname, + java_handle_t *message) +{ + java_handle_t *o; + classinfo *c; + + if (vm_initializing) + exceptions_abort(classname, NULL); + + c = load_class_bootstrap(classname); + + if (c == NULL) + return exceptions_get_exception(); + + o = native_new_and_init_string(c, message); + + if (o == NULL) + return exceptions_get_exception(); + + return o; +} + + +/* exceptions_new_utf_utf ****************************************************** + + Creates an exception object with the given name and initalizes it + with the given utf message. + + IN: + classname....class name in UTF-8 + message......the message as an utf * + + RETURN VALUE: + an exception pointer (in any case -- either it is the newly created + exception, or an exception thrown while trying to create it). + +*******************************************************************************/ + +static java_handle_t *exceptions_new_utf_utf(utf *classname, utf *message) +{ + classinfo *c; + java_handle_t *o; + + if (vm_initializing) + exceptions_abort(classname, message); + + c = load_class_bootstrap(classname); + + if (c == NULL) + return exceptions_get_exception(); + + o = exceptions_new_class_utf(c, message); + + return o; +} + + +/* exceptions_throw_class_utf ************************************************** + + Creates an exception object with the given class, initalizes and + throws it with the given utf message. + + IN: + c ......... exception class + message ... the message as an utf * + +*******************************************************************************/ + +static void exceptions_throw_class_utf(classinfo *c, utf *message) +{ + java_handle_t *o; + + o = exceptions_new_class_utf(c, message); + + exceptions_set_exception(o); +} + + /* exceptions_throw_utf ******************************************************** Creates an exception object with the given name, initalizes and @@ -501,87 +632,6 @@ static void exceptions_throw_utf_cause(utf *classname, java_handle_t *cause) } -/* exceptions_new_utf_javastring *********************************************** - - Creates an exception object with the given name and initalizes it - with the given java/lang/String message. - - IN: - classname....class name in UTF-8 - message......the message as a java.lang.String - - RETURN VALUE: - an exception pointer (in any case -- either it is the newly created - exception, or an exception thrown while trying to create it). - -*******************************************************************************/ - -static java_handle_t *exceptions_new_utf_javastring(utf *classname, - java_handle_t *message) -{ - java_handle_t *o; - classinfo *c; - - if (vm_initializing) - exceptions_abort(classname, NULL); - - c = load_class_bootstrap(classname); - - if (c == NULL) - return exceptions_get_exception(); - - o = native_new_and_init_string(c, message); - - if (o == NULL) - return exceptions_get_exception(); - - return o; -} - - -/* exceptions_new_utf_utf ****************************************************** - - Creates an exception object with the given name and initalizes it - with the given utf message. - - IN: - classname....class name in UTF-8 - message......the message as an utf * - - RETURN VALUE: - an exception pointer (in any case -- either it is the newly created - exception, or an exception thrown while trying to create it). - -*******************************************************************************/ - -static java_handle_t *exceptions_new_utf_utf(utf *classname, utf *message) -{ - classinfo *c; - java_handle_t *s; - java_handle_t *o; - - if (vm_initializing) - exceptions_abort(classname, message); - - c = load_class_bootstrap(classname); - - if (c == NULL) - return exceptions_get_exception(); - - s = javastring_new(message); - - if (s == NULL) - return exceptions_get_exception(); - - o = native_new_and_init_string(c, s); - - if (o == NULL) - return exceptions_get_exception(); - - return o; -} - - /* exceptions_throw_utf_utf **************************************************** Creates an exception object with the given name, initalizes and @@ -794,7 +844,7 @@ void exceptions_throw_classformaterror(classinfo *c, const char *message, ...) void exceptions_throw_classnotfoundexception(utf *name) { - exceptions_throw_utf_utf(utf_java_lang_ClassNotFoundException, name); + exceptions_throw_class_utf(class_java_lang_ClassNotFoundException, name); } @@ -1589,60 +1639,6 @@ void exceptions_throw_stringindexoutofboundsexception(void) } -/* exceptions_classnotfoundexception_to_noclassdeffounderror ******************* - - Check the exception for a ClassNotFoundException. If it is one, - convert it to a NoClassDefFoundError. - -*******************************************************************************/ - -void exceptions_classnotfoundexception_to_noclassdeffounderror(void) -{ - classinfo *c; - java_handle_t *o; - java_handle_t *cause; - java_lang_Throwable *object; - java_lang_String *s; - - /* Load java/lang/ClassNotFoundException for the instanceof - check. */ - - c = load_class_bootstrap(utf_java_lang_ClassNotFoundException); - - if (c == NULL) - return; - - /* Get the cause. */ - - cause = exceptions_get_exception(); - - /* Convert ClassNotFoundException's to NoClassDefFoundError's. */ - - if (builtin_instanceof(cause, c)) { - /* clear exception, because we are calling jit code again */ - - exceptions_clear_exception(); - - /* create new error */ - - object = (java_lang_Throwable *) cause; - LLNI_field_get_ref(object, detailMessage, s); - - o = exceptions_new_utf_javastring(utf_java_lang_NoClassDefFoundError, - (java_handle_t *) s); - - /* we had an exception while creating the error */ - - if (exceptions_get_exception()) - return; - - /* set new exception */ - - exceptions_set_exception(o); - } -} - - /* exceptions_fillinstacktrace ************************************************* Calls the fillInStackTrace-method of the currently thrown diff --git a/src/vm/exceptions.h b/src/vm/exceptions.h index 93958851a..933eb2c33 100644 --- a/src/vm/exceptions.h +++ b/src/vm/exceptions.h @@ -1,9 +1,7 @@ /* src/vm/exceptions.h - exception related functions prototypes - Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien + Copyright (C) 1996-2005, 2006, 2007, 2008 + CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. @@ -131,8 +129,6 @@ void exceptions_throw_nullpointerexception(void); void exceptions_throw_privilegedactionexception(java_handle_t *cause); void exceptions_throw_stringindexoutofboundsexception(void); -void exceptions_classnotfoundexception_to_noclassdeffounderror(void); - java_handle_t *exceptions_fillinstacktrace(void); void exceptions_print_exception(java_handle_t *xptr); diff --git a/src/vm/resolve.c b/src/vm/resolve.c index 3f60dbc57..fddbc29b6 100644 --- a/src/vm/resolve.c +++ b/src/vm/resolve.c @@ -1,9 +1,7 @@ /* src/vm/resolve.c - resolving classes/interfaces/fields/methods - Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien + Copyright (C) 1996-2005, 2006, 2007, 2008 + CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. @@ -55,6 +53,58 @@ /*#define RESOLVE_VERBOSE*/ +/* resolve_handle_pending_exception ******************************************** + + Convert a pending ClassNotFoundException into a + NoClassDefFoundError if requested. + + See: hotspot/src/share/vm/classfile/systemDictionary.cpp + (handle_resolution_exception) + + ARGUMENTS: + classname .... name of the class currently resolved + throwError ... if true throw a NoClassDefFoundError instead of + a ClassNotFoundException + +*******************************************************************************/ + +void resolve_handle_pending_exception(bool throwError) +{ + java_handle_t *e; + + /* Get the current exception. */ + + e = exceptions_get_exception(); + + if (e != NULL) { + if (throwError == true) { + /* Convert ClassNotFoundException to + NoClassDefFoundError. */ + + if (builtin_instanceof(e, class_java_lang_ClassNotFoundException)) { + /* Clear exception, because we are calling Java code + again. */ + + exceptions_clear_exception(); + + /* create new error */ + + exceptions_throw_noclassdeffounderror_cause(e); + } + else { + return; + } + } + else { + /* An exception conversion was not requested. Simply + return. */ + + return; + } + } +} + + /******************************************************************************/ /* CLASS RESOLUTION */ /******************************************************************************/ @@ -177,14 +227,8 @@ bool resolve_class_from_name(classinfo *referer, if (cls == NULL) { cls = load_class_from_classloader(classname, referer->classloader); - if (cls == NULL) { - /* If the exception is a ClassNotFoundException, - convert it to a NoClassDefFoundError. */ - - exceptions_classnotfoundexception_to_noclassdeffounderror(); - + if (cls == NULL) return false; - } } } diff --git a/src/vm/resolve.h b/src/vm/resolve.h index b38b80b76..108217576 100644 --- a/src/vm/resolve.h +++ b/src/vm/resolve.h @@ -1,9 +1,7 @@ /* src/vm/resolve.h - resolving classes/interfaces/fields/methods - Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien + Copyright (C) 1996-2005, 2006, 2007, 2008 + CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. @@ -114,8 +112,11 @@ struct unresolved_method { #define UNRESOLVED_SUBTYPE_SET_EMTPY(stset) \ do { (stset).subtyperefs = NULL; } while(0) + /* function prototypes ********************************************************/ +void resolve_handle_pending_exception(bool throwError); + bool resolve_class_from_name(classinfo* referer,methodinfo *refmethod, utf *classname, resolve_mode_t mode, diff --git a/src/vmcore/class.c b/src/vmcore/class.c index fe5f70a6e..da2ccb284 100644 --- a/src/vmcore/class.c +++ b/src/vmcore/class.c @@ -68,7 +68,7 @@ /* frequently used classes ****************************************************/ -/* important system classes */ +/* Important system classes. */ classinfo *class_java_lang_Object; classinfo *class_java_lang_Class; @@ -88,6 +88,12 @@ classinfo *class_java_lang_VMThread; classinfo *class_java_lang_VMThrowable; #endif +/* Important system exceptions. */ + +classinfo *class_java_lang_Exception; +classinfo *class_java_lang_ClassNotFoundException; +classinfo *class_java_lang_RuntimeException; + #if defined(WITH_CLASSPATH_SUN) classinfo *class_sun_reflect_MagicAccessorImpl; #endif diff --git a/src/vmcore/class.h b/src/vmcore/class.h index 7f25b8f31..4cb801dfd 100644 --- a/src/vmcore/class.h +++ b/src/vmcore/class.h @@ -203,7 +203,7 @@ struct castinfo { /* frequently used classes ****************************************************/ -/* important system classes */ +/* Important system classes. */ extern classinfo *class_java_lang_Object; extern classinfo *class_java_lang_Class; @@ -217,6 +217,12 @@ extern classinfo *class_java_lang_ThreadGroup; extern classinfo *class_java_lang_Throwable; extern classinfo *class_java_io_Serializable; +/* Important system exceptions. */ + +extern classinfo *class_java_lang_Exception; +extern classinfo *class_java_lang_ClassNotFoundException; +extern classinfo *class_java_lang_RuntimeException; + #if defined(WITH_CLASSPATH_GNU) extern classinfo *class_java_lang_VMSystem; extern classinfo *class_java_lang_VMThread; diff --git a/src/vmcore/linker.c b/src/vmcore/linker.c index d1c9c4531..edeee699a 100644 --- a/src/vmcore/linker.c +++ b/src/vmcore/linker.c @@ -279,6 +279,16 @@ void linker_init(void) vm_abort("linker_init: linking failed"); #endif + /* Important system exceptions. */ + + if (!link_class(class_java_lang_Exception)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_java_lang_ClassNotFoundException)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_java_lang_RuntimeException)) + vm_abort("linker_init: linking failed"); /* some classes which may be used more often */ diff --git a/src/vmcore/loader.c b/src/vmcore/loader.c index 6ab5036d3..a2b754e7b 100644 --- a/src/vmcore/loader.c +++ b/src/vmcore/loader.c @@ -197,6 +197,16 @@ void loader_init(void) load_class_bootstrap(utf_new_char("java/lang/VMThrowable")); #endif + /* Important system exceptions. */ + + class_java_lang_Exception = load_class_bootstrap(utf_java_lang_Exception); + + class_java_lang_ClassNotFoundException = + load_class_bootstrap(utf_java_lang_ClassNotFoundException); + + class_java_lang_RuntimeException = + load_class_bootstrap(utf_java_lang_RuntimeException); + /* Some classes which may be used often. */ #if defined(ENABLE_JAVASE) @@ -1643,8 +1653,10 @@ static bool load_class_from_classbuffer_intern(classbuffer *cb) /* XXX This should be done better. */ tc = resolve_classref_or_classinfo_eager(CLASSREF_OR_CLASSINFO(cr), false); - if (tc == NULL) + if (tc == NULL) { + resolve_handle_pending_exception(true); return false; + } /* Interfaces are not allowed as super classes. */ diff --git a/src/vmcore/utf8.c b/src/vmcore/utf8.c index 364526129..fe2da62db 100644 --- a/src/vmcore/utf8.c +++ b/src/vmcore/utf8.c @@ -106,6 +106,7 @@ utf *utf_java_lang_InstantiationException; utf *utf_java_lang_InterruptedException; utf *utf_java_lang_NegativeArraySizeException; utf *utf_java_lang_NullPointerException; +utf *utf_java_lang_RuntimeException; utf *utf_java_lang_StringIndexOutOfBoundsException; utf *utf_java_lang_reflect_InvocationTargetException; @@ -350,6 +351,9 @@ void utf8_init(void) utf_java_lang_NullPointerException = utf_new_char("java/lang/NullPointerException"); + utf_java_lang_RuntimeException = + utf_new_char("java/lang/RuntimeException"); + utf_java_lang_StringIndexOutOfBoundsException = utf_new_char("java/lang/StringIndexOutOfBoundsException"); diff --git a/src/vmcore/utf8.h b/src/vmcore/utf8.h index c3e2ae538..1c6caf69f 100644 --- a/src/vmcore/utf8.h +++ b/src/vmcore/utf8.h @@ -102,6 +102,7 @@ extern utf *utf_java_lang_InstantiationException; extern utf *utf_java_lang_InterruptedException; extern utf *utf_java_lang_NegativeArraySizeException; extern utf *utf_java_lang_NullPointerException; +extern utf *utf_java_lang_RuntimeException; extern utf *utf_java_lang_StringIndexOutOfBoundsException; extern utf *utf_java_lang_reflect_InvocationTargetException; diff --git a/tests/regression/bugzilla/All.java b/tests/regression/bugzilla/All.java index d0183567a..8e144ea2e 100644 --- a/tests/regression/bugzilla/All.java +++ b/tests/regression/bugzilla/All.java @@ -46,6 +46,7 @@ public class All extends TestCase { suite.addTest(new TestSuite(PR52.class)); suite.addTest(new TestSuite(PR57.class)); + suite.addTest(new TestSuite(PR58.class)); return suite; } diff --git a/tests/regression/bugzilla/PR58.java b/tests/regression/bugzilla/PR58.java new file mode 100644 index 000000000..145122644 --- /dev/null +++ b/tests/regression/bugzilla/PR58.java @@ -0,0 +1,59 @@ +/* tests/regression/bugzilla/PR58.java + + Copyright (C) 2008 + CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO + + This file is part of CACAO. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program 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 for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + +*/ + + +import junit.framework.*; +import junit.textui.*; + +import java.io.*; + +public class PR58 extends TestCase { + public static void main(String[] args) { + TestRunner.run(suite()); + } + + public static Test suite() { + return new TestSuite(PR58.class); + } + + class x extends y {} + class y {} + + public void test() { + // Delete the class file which is extended. + new File("PR58$y.class").delete(); + + try { + Class.forName("PR58$x"); + fail("Should throw NoClassDefFoundError"); + } + catch (ClassNotFoundException error) { + fail("Unexpected exception: " + error); + } + catch (NoClassDefFoundError success) { + // Check if the cause is correct. + assertTrue(success.getCause() instanceof ClassNotFoundException); + } + } +} -- 2.25.1