/* src/vm/resolve.c - resolving classes/interfaces/fields/methods
- Copyright (C) 1996-2005, 2006 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.
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
- Contact: cacao@cacaojvm.org
-
- Authors: Edwin Steiner
-
- Changes: Christan Thalinger
-
- $Id: resolve.c 5768 2006-10-13 12:47:03Z edwin $
-
*/
#include <assert.h>
+#include "vm/types.h"
+
#include "mm/memory.h"
-#include "vm/resolve.h"
+
#include "vm/access.h"
-#include "vm/classcache.h"
-#include "vm/descriptor.h"
#include "vm/exceptions.h"
#include "vm/global.h"
-#include "vm/linker.h"
-#include "vm/loader.h"
-#include "vm/options.h"
-#include "vm/stringlocal.h"
+#include "vm/primitive.h"
+#include "vm/resolve.h"
+
#include "vm/jit/jit.h"
#include "vm/jit/verify/typeinfo.h"
+#include "vmcore/classcache.h"
+#include "vmcore/descriptor.h"
+#include "vmcore/linker.h"
+#include "vmcore/loader.h"
+#include "vmcore/options.h"
+
/******************************************************************************/
/* DEBUG HELPERS */
/*#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 */
/******************************************************************************/
bool link,
classinfo **result)
{
- classinfo *cls = NULL;
- char *utf_ptr;
- int len;
-
+ classinfo *cls;
+ char *utf_ptr;
+ int len;
+ char *msg;
+ s4 msglen;
+ utf *u;
+
assert(result);
assert(referer);
assert(classname);
#endif
/* load the class */
- if (!cls) {
- if (!(cls = load_class_from_classloader(classname,
- referer->classloader)))
- return false; /* exception */
+
+ if (cls == NULL) {
+ cls = load_class_from_classloader(classname, referer->classloader);
+
+ if (cls == NULL)
+ return false;
}
}
#endif
/* check access rights of referer to refered class */
+
if (checkaccess && !access_is_accessible_class(referer,cls)) {
- int msglen;
- char *message;
-
- msglen = utf_bytes(cls->name) + utf_bytes(referer->name) + 100;
- message = MNEW(char, msglen);
- strcpy(message, "class is not accessible (");
- utf_cat_classname(message, cls->name);
- strcat(message, " from ");
- utf_cat_classname(message, referer->name);
- strcat(message, ")");
- *exceptionptr = new_exception_message(string_java_lang_IllegalAccessException, message);
- MFREE(message,char,msglen);
+ msglen =
+ utf_bytes(cls->name) +
+ utf_bytes(referer->name) +
+ 100;
+
+ msg = MNEW(char, msglen);
+
+ strcpy(msg, "class is not accessible (");
+ utf_cat_classname(msg, cls->name);
+ strcat(msg, " from ");
+ utf_cat_classname(msg, referer->name);
+ strcat(msg, ")");
+
+ u = utf_new_char(msg);
+
+ MFREE(msg, char, msglen);
+
+ exceptions_throw_illegalaccessexception(u);
+
return false; /* exception */
}
/* resolve_classref_or_classinfo ***********************************************
Resolve a symbolic class reference if necessary
-
+
+ NOTE: If given, refmethod->class is used as the referring class.
+ Otherwise, cls.ref->referer is used.
+
IN:
refmethod........the method from which resolution was triggered
(may be NULL if not applicable)
classinfo **result)
{
classinfo *c;
+ classinfo *referer;
assert(cls.any);
assert(mode == resolveEager || mode == resolveLazy);
if (IS_CLASSREF(cls)) {
/* we must resolve this reference */
- if (!resolve_class_from_name(cls.ref->referer, refmethod, cls.ref->name,
+ /* determine which class to use as the referer */
+
+ /* Common cases are refmethod == NULL or both referring classes */
+ /* being the same, so the referer usually is cls.ref->referer. */
+ /* There is one important case where it is not: When we do a */
+ /* deferred assignability check to a formal argument of a method, */
+ /* we must use refmethod->class (the caller's class) to resolve */
+ /* the type of the formal argument. */
+
+ referer = (refmethod) ? refmethod->class : cls.ref->referer;
+
+ if (!resolve_class_from_name(referer, refmethod, cls.ref->name,
mode, checkaccess, link, &c))
goto return_exception;
}
+/* resolve_classref_or_classinfo_eager *****************************************
+
+ Resolve a symbolic class reference eagerly if necessary.
+ No attempt is made to link the class.
+
+ IN:
+ cls..............class reference or classinfo
+ checkaccess......if true, access rights to the class are checked
+
+ RETURN VALUE:
+ classinfo *......the resolved class
+ NULL.............an exception has been thrown
+
+*******************************************************************************/
+
+classinfo *resolve_classref_or_classinfo_eager(classref_or_classinfo cls,
+ bool checkaccess)
+{
+ classinfo *c;
+
+ if (!resolve_classref_or_classinfo(NULL, cls, resolveEager, checkaccess, false, &c))
+ return NULL;
+
+ return c;
+}
+
+
/* resolve_class_from_typedesc *************************************************
Return a classinfo * for the given type descriptor
}
else {
/* a primitive type */
- cls = primitivetype_table[d->decltype].class_primitive;
+
+ cls = primitive_class_get_by_type(d->decltype);
+
assert(cls->state & CLASS_LOADED);
+
if (!(cls->state & CLASS_LINKED))
if (!link_class(cls))
return false; /* exception */
}
+
assert(cls);
assert(cls->state & CLASS_LOADED);
assert(!link || (cls->state & CLASS_LINKED));
resolve_mode_t mode,
resolve_err_t error)
{
- classinfo *subclass;
- typeinfo subti;
- typecheck_result r;
+ classinfo *subclass;
+ typeinfo subti;
+ typecheck_result r;
+ char *msg;
+ s4 msglen;
+ utf *u;
assert(refmethod);
assert(subtype.any);
/* the subclass could not be resolved. therefore we are sure that */
/* no instances of this subclass will ever exist -> skip this test */
/* XXX this assumes that class loading has invariant results (as in JVM spec) */
- *exceptionptr = NULL;
+ exceptions_clear_exception();
return resolveSucceeded;
}
if (!subclass)
if (!r) {
/* sub class relationship is false */
- char *message;
- int msglen;
-
#if defined(RESOLVE_VERBOSE)
printf("SUBTYPE CHECK FAILED!\n");
#endif
- msglen = utf_bytes(subclass->name) + utf_bytes(CLASSREF_OR_CLASSINFO_NAME(supertype)) + 200;
- message = MNEW(char, msglen);
- strcpy(message, (error == resolveIllegalAccessError) ?
- "illegal access to protected member ("
- : "subtype constraint violated (");
- utf_cat_classname(message, subclass->name);
- strcat(message, " is not a subclass of ");
- utf_cat_classname(message, CLASSREF_OR_CLASSINFO_NAME(supertype));
- strcat(message, ")");
+ msglen =
+ utf_bytes(subclass->name) +
+ utf_bytes(CLASSREF_OR_CLASSINFO_NAME(supertype))
+ + 200;
+
+ msg = MNEW(char, msglen);
+
+ strcpy(msg, (error == resolveIllegalAccessError) ?
+ "illegal access to protected member (" :
+ "subtype constraint violated (");
+
+ utf_cat_classname(msg, subclass->name);
+ strcat(msg, " is not a subclass of ");
+ utf_cat_classname(msg, CLASSREF_OR_CLASSINFO_NAME(supertype));
+ strcat(msg, ")");
+
+ u = utf_new_char(msg);
+
if (error == resolveIllegalAccessError)
- *exceptionptr = new_exception_message(string_java_lang_IllegalAccessException, message);
+ exceptions_throw_illegalaccessexception(u);
else
- *exceptionptr = exceptions_new_linkageerror(message, NULL);
- MFREE(message, char, msglen);
+ exceptions_throw_linkageerror(msg, NULL);
+
+ /* ATTENTION: We probably need msg for
+ exceptions_throw_linkageerror. */
+
+ MFREE(msg, char, msglen);
+
return resolveFailed; /* exception */
}
}
#endif /* ENABLE_VERIFIER */
+/* resolve_class_eager_no_access_check *****************************************
+
+ Resolve an unresolved class reference eagerly. The class is also linked.
+ Access rights are _not_ checked.
+
+ IN:
+ ref..............struct containing the reference
+
+ RETURN VALUE:
+ classinfo * to the class, or
+ NULL if an exception has been thrown
+
+*******************************************************************************/
+
+#ifdef ENABLE_VERIFIER
+classinfo * resolve_class_eager_no_access_check(unresolved_class *ref)
+{
+ classinfo *c;
+
+ if (!resolve_class(ref, resolveEager, false, &c))
+ return NULL;
+
+ return c;
+}
+#endif /* ENABLE_VERIFIER */
+
/******************************************************************************/
/* FIELD RESOLUTION */
/******************************************************************************/
bool isstatic,
bool isput)
{
- classinfo *declarer;
- classinfo *referer;
- resolve_result_t result;
+ classinfo *declarer;
+ classinfo *referer;
+ resolve_result_t result;
constant_classref *fieldtyperef;
+ char *msg;
+ s4 msglen;
+ utf *u;
assert(refmethod);
assert(fieldref);
if (((fi->flags & ACC_STATIC) != 0) != isstatic) {
/* a static field is accessed via an instance, or vice versa */
- *exceptionptr =
- new_exception_message(string_java_lang_IncompatibleClassChangeError,
- (fi->flags & ACC_STATIC) ? "static field accessed via instance"
- : "instance field accessed without instance");
+ exceptions_throw_incompatibleclasschangeerror(declarer,
+ (fi->flags & ACC_STATIC)
+ ? "static field accessed via instance"
+ : "instance field accessed without instance");
+
return resolveFailed;
}
/* check access rights */
if (!access_is_accessible_member(referer,declarer,fi->flags)) {
- int msglen;
- char *message;
-
- msglen = utf_bytes(declarer->name) + utf_bytes(fi->name) + utf_bytes(referer->name) + 100;
- message = MNEW(char, msglen);
- strcpy(message, "field is not accessible (");
- utf_cat_classname(message, declarer->name);
- strcat(message, ".");
- utf_cat(message, fi->name);
- strcat(message, " from ");
- utf_cat_classname(message, referer->name);
- strcat(message, ")");
- *exceptionptr = new_exception_message(string_java_lang_IllegalAccessException, message);
- MFREE(message,char,msglen);
+ msglen =
+ utf_bytes(declarer->name) +
+ utf_bytes(fi->name) +
+ utf_bytes(referer->name) +
+ 100;
+
+ msg = MNEW(char, msglen);
+
+ strcpy(msg, "field is not accessible (");
+ utf_cat_classname(msg, declarer->name);
+ strcat(msg, ".");
+ utf_cat(msg, fi->name);
+ strcat(msg, " from ");
+ utf_cat_classname(msg, referer->name);
+ strcat(msg, ")");
+
+ u = utf_new_char(msg);
+
+ MFREE(msg, char, msglen);
+
+ exceptions_throw_illegalaccessexception(u);
+
return resolveFailed; /* exception */
}
/* this error must not be reported now. (It will be reported */
/* if eager resolving of this field is ever tried.) */
- *exceptionptr = NULL;
+ exceptions_clear_exception();
return resolveDeferred; /* be lazy */
}
/* this error must not be reported now. (It will be reported */
/* if eager resolving of this field is ever tried.) */
- *exceptionptr = NULL;
+ exceptions_clear_exception();
return true; /* be lazy */
}
/* lookup starting with the direct super class of referer */
if ((referer->flags & ACC_SUPER) != 0) {
- mi = class_resolvemethod(referer->super.cls,
+ mi = class_resolvemethod(referer->super,
mi->name,
mi->descriptor);
if (mi == NULL) {
/* the spec calls for an AbstractMethodError in this case */
+
exceptions_throw_abstractmethoderror();
+
return NULL;
}
}
{
classinfo *declarer;
classinfo *referer;
+ char *msg;
+ s4 msglen;
+ utf *u;
assert(refmethod);
assert(methodref);
if (((mi->flags & ACC_STATIC) != 0) != (invokestatic != false)) {
/* a static method is accessed via an instance, or vice versa */
- *exceptionptr =
- new_exception_message(string_java_lang_IncompatibleClassChangeError,
- (mi->flags & ACC_STATIC) ? "static method called via instance"
- : "instance method called without instance");
+ exceptions_throw_incompatibleclasschangeerror(declarer,
+ (mi->flags & ACC_STATIC)
+ ? "static method called via instance"
+ : "instance method called without instance");
+
return resolveFailed;
}
/* check access rights */
if (!access_is_accessible_member(referer,declarer,mi->flags)) {
- int msglen;
- char *message;
-
/* XXX clean this up. this should be in exceptions.c */
- msglen = utf_bytes(declarer->name) + utf_bytes(mi->name) +
- utf_bytes(mi->descriptor) + utf_bytes(referer->name) + 100;
- message = MNEW(char, msglen);
- strcpy(message, "method is not accessible (");
- utf_cat_classname(message, declarer->name);
- strcat(message, ".");
- utf_cat(message, mi->name);
- utf_cat(message, mi->descriptor);
- strcat(message," from ");
- utf_cat_classname(message, referer->name);
- strcat(message,")");
- *exceptionptr = new_exception_message(string_java_lang_IllegalAccessException, message);
- MFREE(message, char, msglen);
+
+ msglen =
+ utf_bytes(declarer->name) +
+ utf_bytes(mi->name) +
+ utf_bytes(mi->descriptor) +
+ utf_bytes(referer->name) +
+ 100;
+
+ msg = MNEW(char, msglen);
+
+ strcpy(msg, "method is not accessible (");
+ utf_cat_classname(msg, declarer->name);
+ strcat(msg, ".");
+ utf_cat(msg, mi->name);
+ utf_cat(msg, mi->descriptor);
+ strcat(msg, " from ");
+ utf_cat_classname(msg, referer->name);
+ strcat(msg, ")");
+
+ u = utf_new_char(msg);
+
+ MFREE(msg, char, msglen);
+
+ exceptions_throw_illegalaccessexception(u);
+
return resolveFailed; /* exception */
}
/* this error must not be reported now. (It will be reported */
/* if eager resolving of this method is ever tried.) */
- *exceptionptr = NULL;
+ exceptions_clear_exception();
return resolveDeferred; /* be lazy */
}
/* this error must not be reported now. (It will be reported */
/* if eager resolving of this method is ever tried.) */
- *exceptionptr = NULL;
+ exceptions_clear_exception();
return true; /* be lazy */
}
}
#endif /* !defined(NDEBUG) */
+
/*
* These are local overrides for various environment variables in Emacs.
* Please do not remove this and leave it at the end of the file, where
* End:
* vim:noexpandtab:sw=4:ts=4:
*/
-