Authors: Edwin Steiner
- Changes:
+ Changes: Christan Thalinger
- $Id: resolve.c 2195 2005-04-03 16:53:16Z edwin $
+ $Id: resolve.c 3811 2005-11-28 16:23:40Z edwin $
*/
#include "vm/resolve.h"
#include "vm/access.h"
#include "vm/classcache.h"
+#include "vm/descriptor.h"
#include "vm/exceptions.h"
-#include "vm/loader.h"
#include "vm/linker.h"
-#include "vm/classcache.h"
-#include "vm/descriptor.h"
+#include "vm/loader.h"
+#include "vm/stringlocal.h"
#include "vm/jit/jit.h"
#include "vm/jit/verify/typeinfo.h"
/*#define RESOLVE_VERBOSE*/
-#ifndef NDEBUG
-#define RESOLVE_DEBUG
-#endif
-
-#ifdef RESOLVE_DEBUG
-#define RESOLVE_ASSERT(cond) assert(cond)
-#else
-#define RESOLVE_ASSERT(cond)
-#endif
-
/******************************************************************************/
/* CLASS RESOLUTION */
/******************************************************************************/
-/* resolve symbolic class reference -- see resolve.h */
-bool
-resolve_class(classinfo *referer,methodinfo *refmethod,
- utf *classname,
- resolve_mode_t mode,
- classinfo **result)
+/* resolve_class_from_name *****************************************************
+
+ Resolve a symbolic class reference
+
+ IN:
+ referer..........the class containing the reference
+ refmethod........the method from which resolution was triggered
+ (may be NULL if not applicable)
+ classname........class name to resolve
+ mode.............mode of resolution:
+ resolveLazy...only resolve if it does not
+ require loading classes
+ resolveEager..load classes if necessary
+ checkaccess......if true, access rights to the class are checked
+ link.............if true, guarantee that the returned class, if any,
+ has been linked
+
+ OUT:
+ *result..........set to result of resolution, or to NULL if
+ the reference has not been resolved
+ In the case of an exception, *result is
+ guaranteed to be set to NULL.
+
+ RETURN VALUE:
+ true.............everything ok
+ (*result may still be NULL for resolveLazy)
+ false............an exception has been thrown
+
+ NOTE:
+ The returned class is *not* guaranteed to be linked!
+ (It is guaranteed to be loaded, though.)
+
+*******************************************************************************/
+
+bool resolve_class_from_name(classinfo *referer,
+ methodinfo *refmethod,
+ utf *classname,
+ resolve_mode_t mode,
+ bool checkaccess,
+ bool link,
+ classinfo **result)
{
classinfo *cls = NULL;
char *utf_ptr;
int len;
- RESOLVE_ASSERT(result);
- RESOLVE_ASSERT(referer);
- RESOLVE_ASSERT(classname);
- RESOLVE_ASSERT(mode == resolveLazy || mode == resolveEager);
+ assert(result);
+ assert(referer);
+ assert(classname);
+ assert(mode == resolveLazy || mode == resolveEager);
*result = NULL;
#ifdef RESOLVE_VERBOSE
- fprintf(stderr,"resolve_class(");
+ fprintf(stderr,"resolve_class_from_name(");
utf_fprint(stderr,referer->name);
- fprintf(stderr,",");
+ fprintf(stderr,",%p,",referer->classloader);
utf_fprint(stderr,classname);
- fprintf(stderr,")\n");
+ fprintf(stderr,",%d,%d)\n",(int)checkaccess,(int)link);
#endif
/* lookup if this class has already been loaded */
- cls = classcache_lookup(referer->classloader,classname);
+
+ cls = classcache_lookup(referer->classloader, classname);
#ifdef RESOLVE_VERBOSE
fprintf(stderr," lookup result: %p\n",(void*)cls);
#endif
-
+
if (!cls) {
/* resolve array types */
+
if (classname->text[0] == '[') {
utf_ptr = classname->text + 1;
len = classname->blength - 1;
+
/* classname is an array type name */
+
switch (*utf_ptr) {
case 'L':
utf_ptr++;
case '[':
/* the component type is a reference type */
/* resolve the component type */
- if (!resolve_class(referer,refmethod,
+ if (!resolve_class_from_name(referer,refmethod,
utf_new(utf_ptr,len),
- mode,&cls))
+ mode,checkaccess,link,&cls))
return false; /* exception */
if (!cls) {
- RESOLVE_ASSERT(mode == resolveLazy);
+ assert(mode == resolveLazy);
return true; /* be lazy */
}
/* create the array class */
/* load the class */
if (!cls) {
- if (!load_class_from_classloader(classname,referer->classloader,&cls))
+ if (!(cls = load_class_from_classloader(classname,
+ referer->classloader)))
return false; /* exception */
}
}
/* the class is now loaded */
- RESOLVE_ASSERT(cls);
- RESOLVE_ASSERT(cls->loaded);
+ assert(cls);
+ assert(cls->loaded);
#ifdef RESOLVE_VERBOSE
fprintf(stderr," checking access rights...\n");
#endif
/* check access rights of referer to refered class */
- if (!is_accessible_class(referer,cls)) {
- *exceptionptr = new_exception_message(string_java_lang_IllegalAccessException,
- "class is not accessible XXX add message");
+ if (checkaccess && !access_is_accessible_class(referer,cls)) {
+ int msglen;
+ char *message;
+
+ msglen = utf_strlen(cls->name) + utf_strlen(referer->name) + 100;
+ message = MNEW(char,msglen);
+ strcpy(message,"class is not accessible (");
+ utf_sprint_classname(message+strlen(message),cls->name);
+ strcat(message," from ");
+ utf_sprint_classname(message+strlen(message),referer->name);
+ strcat(message,")");
+ *exceptionptr = new_exception_message(string_java_lang_IllegalAccessException,message);
+ MFREE(message,char,msglen);
return false; /* exception */
}
+ /* link the class if necessary */
+ if (link) {
+ if (!cls->linked)
+ if (!link_class(cls))
+ return false; /* exception */
+ assert(cls->linked);
+ }
+
/* resolution succeeds */
#ifdef RESOLVE_VERBOSE
fprintf(stderr," success.\n");
return true;
}
-bool
-resolve_classref(methodinfo *refmethod,
- constant_classref *ref,
- resolve_mode_t mode,
- bool link,
- classinfo **result)
+/* resolve_classref ************************************************************
+
+ Resolve a symbolic class reference
+
+ IN:
+ refmethod........the method from which resolution was triggered
+ (may be NULL if not applicable)
+ ref..............class reference
+ mode.............mode of resolution:
+ resolveLazy...only resolve if it does not
+ require loading classes
+ resolveEager..load classes if necessary
+ checkaccess......if true, access rights to the class are checked
+ link.............if true, guarantee that the returned class, if any,
+ has been linked
+
+ OUT:
+ *result..........set to result of resolution, or to NULL if
+ the reference has not been resolved
+ In the case of an exception, *result is
+ guaranteed to be set to NULL.
+
+ RETURN VALUE:
+ true.............everything ok
+ (*result may still be NULL for resolveLazy)
+ false............an exception has been thrown
+
+*******************************************************************************/
+
+bool resolve_classref(methodinfo *refmethod,
+ constant_classref *ref,
+ resolve_mode_t mode,
+ bool checkaccess,
+ bool link,
+ classinfo **result)
{
- return resolve_classref_or_classinfo(refmethod,CLASSREF_OR_CLASSINFO(ref),mode,link,result);
+ return resolve_classref_or_classinfo(refmethod,CLASSREF_OR_CLASSINFO(ref),mode,checkaccess,link,result);
}
-bool
-resolve_classref_or_classinfo(methodinfo *refmethod,
- classref_or_classinfo cls,
- resolve_mode_t mode,
- bool link,
- classinfo **result)
+/* resolve_classref_or_classinfo ***********************************************
+
+ Resolve a symbolic class reference if necessary
+
+ IN:
+ refmethod........the method from which resolution was triggered
+ (may be NULL if not applicable)
+ cls..............class reference or classinfo
+ mode.............mode of resolution:
+ resolveLazy...only resolve if it does not
+ require loading classes
+ resolveEager..load classes if necessary
+ checkaccess......if true, access rights to the class are checked
+ link.............if true, guarantee that the returned class, if any,
+ has been linked
+
+ OUT:
+ *result..........set to result of resolution, or to NULL if
+ the reference has not been resolved
+ In the case of an exception, *result is
+ guaranteed to be set to NULL.
+
+ RETURN VALUE:
+ true.............everything ok
+ (*result may still be NULL for resolveLazy)
+ false............an exception has been thrown
+
+*******************************************************************************/
+
+bool resolve_classref_or_classinfo(methodinfo *refmethod,
+ classref_or_classinfo cls,
+ resolve_mode_t mode,
+ bool checkaccess,
+ bool link,
+ classinfo **result)
{
- classinfo *c;
+ classinfo *c;
- RESOLVE_ASSERT(cls.any);
- RESOLVE_ASSERT(mode == resolveEager || mode == resolveLazy);
- RESOLVE_ASSERT(result);
+ assert(cls.any);
+ assert(mode == resolveEager || mode == resolveLazy);
+ assert(result);
#ifdef RESOLVE_VERBOSE
fprintf(stderr,"resolve_classref_or_classinfo(");
utf_fprint(stderr,(IS_CLASSREF(cls)) ? cls.ref->name : cls.cls->name);
- fprintf(stderr,",%i,%i)\n",mode,link);
+ fprintf(stderr,",%i,%i,%i)\n",mode,(int)checkaccess,(int)link);
#endif
*result = NULL;
if (IS_CLASSREF(cls)) {
/* we must resolve this reference */
- if (!resolve_class(cls.ref->referer,refmethod,cls.ref->name,
- mode,&c))
- return false; /* exception */
- }
- else {
+
+ if (!resolve_class_from_name(cls.ref->referer, refmethod, cls.ref->name,
+ mode, checkaccess, link, &c))
+ goto return_exception;
+
+ } else {
/* cls has already been resolved */
c = cls.cls;
- RESOLVE_ASSERT(c->loaded);
+ assert(c->loaded);
}
- RESOLVE_ASSERT(c || (mode == resolveLazy));
+ assert(c || (mode == resolveLazy));
if (!c)
return true; /* be lazy */
- RESOLVE_ASSERT(c);
- RESOLVE_ASSERT(c->loaded);
+ assert(c);
+ assert(c->loaded);
if (link) {
if (!c->linked)
if (!link_class(c))
- return false; /* exception */
- RESOLVE_ASSERT(c->linked);
+ goto return_exception;
+
+ assert(c->linked);
}
/* succeeded */
*result = c;
return true;
+
+ return_exception:
+ *result = NULL;
+ return false;
}
-bool
-resolve_class_from_typedesc(typedesc *d,bool link,classinfo **result)
+
+/* resolve_class_from_typedesc *************************************************
+
+ Return a classinfo * for the given type descriptor
+
+ IN:
+ d................type descriptor
+ checkaccess......if true, access rights to the class are checked
+ link.............if true, guarantee that the returned class, if any,
+ has been linked
+ OUT:
+ *result..........set to result of resolution, or to NULL if
+ the reference has not been resolved
+ In the case of an exception, *result is
+ guaranteed to be set to NULL.
+
+ RETURN VALUE:
+ true.............everything ok
+ false............an exception has been thrown
+
+ NOTE:
+ This function always resolved eagerly.
+
+*******************************************************************************/
+
+bool resolve_class_from_typedesc(typedesc *d, bool checkaccess, bool link, classinfo **result)
{
classinfo *cls;
- RESOLVE_ASSERT(d);
- RESOLVE_ASSERT(result);
+ assert(d);
+ assert(result);
*result = NULL;
#ifdef RESOLVE_VERBOSE
fprintf(stderr,"resolve_class_from_typedesc(");
descriptor_debug_print_typedesc(stderr,d);
- fprintf(stderr,",%i)\n",link);
+ fprintf(stderr,",%i,%i)\n",(int)checkaccess,(int)link);
#endif
if (d->classref) {
/* a reference type */
if (!resolve_classref_or_classinfo(NULL,CLASSREF_OR_CLASSINFO(d->classref),
- resolveEager,link,&cls))
+ resolveEager,checkaccess,link,&cls))
return false; /* exception */
}
else {
/* a primitive type */
cls = primitivetype_table[d->decltype].class_primitive;
- RESOLVE_ASSERT(cls->loaded);
+ assert(cls->loaded);
if (!cls->linked)
if (!link_class(cls))
return false; /* exception */
}
- RESOLVE_ASSERT(cls);
- RESOLVE_ASSERT(cls->loaded);
- RESOLVE_ASSERT(!link || cls->linked);
+ assert(cls);
+ assert(cls->loaded);
+ assert(!link || cls->linked);
#ifdef RESOLVE_VERBOSE
fprintf(stderr," result = ");utf_fprint(stderr,cls->name);fprintf(stderr,"\n");
/* SUBTYPE SET CHECKS */
/******************************************************************************/
-/* for documentation see resolve.h */
-bool
-resolve_and_check_subtype_set(classinfo *referer,methodinfo *refmethod,
- unresolved_subtype_set *ref,
- classref_or_classinfo typeref,
- bool reversed,
- resolve_mode_t mode,
- resolve_err_t error,
- bool *checked)
+#ifdef ENABLE_VERIFIER
+
+/* resolve_and_check_subtype_set ***********************************************
+
+ Resolve the references in the given set and test subtype relationships
+
+ IN:
+ referer..........the class containing the references
+ refmethod........the method triggering the resolution
+ ref..............a set of class/interface references
+ (may be empty)
+ type.............the type to test against the set
+ reversed.........if true, test if type is a subtype of
+ the set members, instead of the other
+ way round
+ mode.............mode of resolution:
+ resolveLazy...only resolve if it does not
+ require loading classes
+ resolveEager..load classes if necessary
+ error............which type of exception to throw if
+ the test fails. May be:
+ resolveLinkageError, or
+ resolveIllegalAccessError
+ IMPORTANT: If error==resolveIllegalAccessError,
+ then array types in the set are skipped.
+
+ OUT:
+ *checked.........set to true if all checks were performed,
+ otherwise set to false
+ (This is guaranteed to be true if mode was
+ resolveEager and no exception occured.)
+ If checked == NULL, this parameter is not used.
+
+ RETURN VALUE:
+ true.............the check succeeded
+ false............the check failed. An exception has been
+ thrown.
+
+ NOTE:
+ The references in the set are resolved first, so any
+ exception which may occurr during resolution may
+ be thrown by this function.
+
+*******************************************************************************/
+
+bool resolve_and_check_subtype_set(classinfo *referer,methodinfo *refmethod,
+ unresolved_subtype_set *ref,
+ classref_or_classinfo typeref,
+ bool reversed,
+ resolve_mode_t mode,
+ resolve_err_t error,
+ bool *checked)
{
classref_or_classinfo *setp;
classinfo *result;
classinfo *type;
typeinfo resultti;
typeinfo typeti;
+ char *message;
+ int msglen;
+ typecheck_result r;
- RESOLVE_ASSERT(referer);
- RESOLVE_ASSERT(ref);
- RESOLVE_ASSERT(typeref.any);
- RESOLVE_ASSERT(mode == resolveLazy || mode == resolveEager);
- RESOLVE_ASSERT(error == resolveLinkageError || error == resolveIllegalAccessError);
+ assert(referer);
+ assert(ref);
+ assert(typeref.any);
+ assert(mode == resolveLazy || mode == resolveEager);
+ assert(error == resolveLinkageError || error == resolveIllegalAccessError);
#ifdef RESOLVE_VERBOSE
fprintf(stderr,"resolve_and_check_subtype_set\n");
*checked = false;
/* first resolve the type if necessary */
- if (!resolve_classref_or_classinfo(refmethod,typeref,mode,true,&type))
+ if (!resolve_classref_or_classinfo(refmethod,typeref,mode,false,true,&type))
return false; /* exception */
if (!type)
return true; /* be lazy */
- RESOLVE_ASSERT(type);
- RESOLVE_ASSERT(type->loaded);
- RESOLVE_ASSERT(type->linked);
- TYPEINFO_INIT_CLASSINFO(typeti,type);
+ assert(type);
+ assert(type->loaded);
+ assert(type->linked);
+ typeinfo_init_classinfo(&typeti,type);
for (; setp->any; ++setp) {
/* first resolve the set member if necessary */
- if (!resolve_classref_or_classinfo(refmethod,*setp,mode,true,&result))
- return false; /* exception */
+ if (!resolve_classref_or_classinfo(refmethod,*setp,mode,false,true,&result)) {
+ /* the type could not be resolved. therefore we are sure that */
+ /* no instances of this type will ever exist -> skip this test */
+ /* XXX this assumes that class loading has invariant results (as in JVM spec) */
+ *exceptionptr = NULL;
+ continue;
+ }
if (!result)
return true; /* be lazy */
- RESOLVE_ASSERT(result);
- RESOLVE_ASSERT(result->loaded);
- RESOLVE_ASSERT(result->linked);
+ assert(result);
+ assert(result->loaded);
+ assert(result->linked);
+
+
+ /* do not check access to protected members of arrays */
+ if (error == resolveIllegalAccessError && result->name->text[0] == '[') {
+ continue;
+ }
#ifdef RESOLVE_VERBOSE
fprintf(stderr,"performing subclass test:\n");
#endif
/* now check the subtype relationship */
- TYPEINFO_INIT_CLASSINFO(resultti,result);
+ typeinfo_init_classinfo(&resultti,result);
if (reversed) {
/* we must test against `true` because `MAYBE` is also != 0 */
- if (true != typeinfo_is_assignable_to_class(&typeti,CLASSREF_OR_CLASSINFO(result))) {
+ r = typeinfo_is_assignable_to_class(&typeti,CLASSREF_OR_CLASSINFO(result));
+ if (r == typecheck_FAIL)
+ return false;
+ if (r != typecheck_TRUE) {
#ifdef RESOLVE_VERBOSE
fprintf(stderr,"reversed subclass test failed\n");
#endif
}
else {
/* we must test against `true` because `MAYBE` is also != 0 */
- if (true != typeinfo_is_assignable_to_class(&resultti,CLASSREF_OR_CLASSINFO(type))) {
+ r = typeinfo_is_assignable_to_class(&resultti,CLASSREF_OR_CLASSINFO(type));
+ if (r == typecheck_FAIL)
+ return false;
+ if (r != typecheck_TRUE) {
#ifdef RESOLVE_VERBOSE
fprintf(stderr,"subclass test failed\n");
#endif
return true;
throw_error:
+ msglen = utf_strlen(result->name) + utf_strlen(type->name) + 200;
+ message = MNEW(char,msglen);
+ strcpy(message,(error == resolveIllegalAccessError) ?
+ "illegal access to protected member ("
+ : "subtype constraint violated (");
+ utf_sprint_classname(message+strlen(message),result->name);
+ strcat(message," is not a subclass of ");
+ utf_sprint_classname(message+strlen(message),type->name);
+ strcat(message,")");
if (error == resolveIllegalAccessError)
- *exceptionptr = new_exception_message(string_java_lang_IllegalAccessException,
- "illegal access to protected member XXX add message");
+ *exceptionptr = new_exception_message(string_java_lang_IllegalAccessException,message);
else
- *exceptionptr = new_exception_message(string_java_lang_LinkageError,
- "subtype constraint violated XXX add message");
+ *exceptionptr = exceptions_new_linkageerror(message,NULL);
+ MFREE(message,char,msglen);
return false; /* exception */
}
+#endif /* ENABLE_VERIFIER */
+
+/******************************************************************************/
+/* CLASS RESOLUTION */
+/******************************************************************************/
+
+/* resolve_class ***************************************************************
+
+ Resolve an unresolved class reference. The class is also linked.
+
+ IN:
+ ref..............struct containing the reference
+ mode.............mode of resolution:
+ resolveLazy...only resolve if it does not
+ require loading classes
+ resolveEager..load classes if necessary
+ checkaccess......if true, access rights to the class are checked
+
+ OUT:
+ *result..........set to the result of resolution, or to NULL if
+ the reference has not been resolved
+ In the case of an exception, *result is
+ guaranteed to be set to NULL.
+
+ RETURN VALUE:
+ true.............everything ok
+ (*result may still be NULL for resolveLazy)
+ false............an exception has been thrown
+
+*******************************************************************************/
+
+#ifdef ENABLE_VERIFIER
+bool resolve_class(unresolved_class *ref,
+ resolve_mode_t mode,
+ bool checkaccess,
+ classinfo **result)
+{
+ classinfo *cls;
+ bool checked;
+
+ assert(ref);
+ assert(result);
+ assert(mode == resolveLazy || mode == resolveEager);
+
+ *result = NULL;
+
+#ifdef RESOLVE_VERBOSE
+ unresolved_class_debug_dump(ref,stderr);
+#endif
+
+ /* first we must resolve the class */
+ if (!resolve_classref(ref->referermethod,
+ ref->classref,mode,checkaccess,true,&cls))
+ {
+ /* the class reference could not be resolved */
+ return false; /* exception */
+ }
+ if (!cls)
+ return true; /* be lazy */
+
+ assert(cls);
+ assert(cls->loaded && cls->linked);
+
+ /* now we check the subtype constraints */
+ if (!resolve_and_check_subtype_set(ref->classref->referer,ref->referermethod,
+ &(ref->subtypeconstraints),
+ CLASSREF_OR_CLASSINFO(cls),
+ false,
+ mode,
+ resolveLinkageError,&checked))
+ {
+ return false; /* exception */
+ }
+ if (!checked)
+ return true; /* be lazy */
+
+ /* succeed */
+ *result = cls;
+ return true;
+}
+#endif /* ENABLE_VERIFIER */
+
+/* resolve_classref_eager ******************************************************
+
+ Resolve an unresolved class reference eagerly. The class is also linked and
+ access rights to the class are checked.
+
+ IN:
+ ref..............constant_classref to the class
+
+ RETURN VALUE:
+ classinfo * to the class, or
+ NULL if an exception has been thrown
+
+*******************************************************************************/
+
+classinfo * resolve_classref_eager(constant_classref *ref)
+{
+ classinfo *c;
+
+ if (!resolve_classref(NULL,ref,resolveEager,true,true,&c))
+ return NULL;
+
+ return c;
+}
+
+/* resolve_classref_eager_nonabstract ******************************************
+
+ Resolve an unresolved class reference eagerly. The class is also linked and
+ access rights to the class are checked. A check is performed that the class
+ is not abstract.
+
+ IN:
+ ref..............constant_classref to the class
+
+ RETURN VALUE:
+ classinfo * to the class, or
+ NULL if an exception has been thrown
+
+*******************************************************************************/
+
+classinfo * resolve_classref_eager_nonabstract(constant_classref *ref)
+{
+ classinfo *c;
+
+ if (!resolve_classref(NULL,ref,resolveEager,true,true,&c))
+ return NULL;
+
+ /* ensure that the class is not abstract */
+
+ if (c->flags & ACC_ABSTRACT) {
+ *exceptionptr = new_verifyerror(NULL,"creating instance of abstract class");
+ return NULL;
+ }
+
+ return c;
+}
+
+/* resolve_class_eager *********************************************************
+
+ Resolve an unresolved class reference eagerly. The class is also linked and
+ access rights to the class are 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(unresolved_class *ref)
+{
+ classinfo *c;
+
+ if (!resolve_class(ref,resolveEager,true,&c))
+ return NULL;
+
+ return c;
+}
+#endif /* ENABLE_VERIFIER */
+
/******************************************************************************/
/* FIELD RESOLUTION */
/******************************************************************************/
-/* for documentation see resolve.h */
-bool
-resolve_field(unresolved_field *ref,
- resolve_mode_t mode,
- fieldinfo **result)
+/* resolve_field ***************************************************************
+
+ Resolve an unresolved field reference
+
+ IN:
+ ref..............struct containing the reference
+ mode.............mode of resolution:
+ resolveLazy...only resolve if it does not
+ require loading classes
+ resolveEager..load classes if necessary
+
+ OUT:
+ *result..........set to the result of resolution, or to NULL if
+ the reference has not been resolved
+ In the case of an exception, *result is
+ guaranteed to be set to NULL.
+
+ RETURN VALUE:
+ true.............everything ok
+ (*result may still be NULL for resolveLazy)
+ false............an exception has been thrown
+
+*******************************************************************************/
+
+bool resolve_field(unresolved_field *ref,
+ resolve_mode_t mode,
+ fieldinfo **result)
{
classinfo *referer;
classinfo *container;
fieldinfo *fi;
bool checked;
- RESOLVE_ASSERT(ref);
- RESOLVE_ASSERT(result);
- RESOLVE_ASSERT(mode == resolveLazy || mode == resolveEager);
+ assert(ref);
+ assert(result);
+ assert(mode == resolveLazy || mode == resolveEager);
*result = NULL;
#endif
/* the class containing the reference */
+
referer = ref->fieldref->classref->referer;
- RESOLVE_ASSERT(referer);
+ assert(referer);
/* first we must resolve the class containg the field */
- if (!resolve_class(referer,ref->referermethod,
- ref->fieldref->classref->name,mode,&container))
+ if (!resolve_class_from_name(referer,ref->referermethod,
+ ref->fieldref->classref->name,mode,true,true,&container))
{
/* the class reference could not be resolved */
return false; /* exception */
if (!container)
return true; /* be lazy */
- RESOLVE_ASSERT(container);
- RESOLVE_ASSERT(container->loaded && container->linked);
+ assert(container);
+ assert(container->loaded && container->linked);
/* now we must find the declaration of the field in `container`
* or one of its superclasses */
fi = class_resolvefield(container,
ref->fieldref->name,ref->fieldref->descriptor,
referer,true);
- if (!fi)
+ if (!fi) {
+ if (mode == resolveLazy) {
+ /* The field does not exist. But since we were called lazily, */
+ /* this error must not be reported now. (It will be reported */
+ /* if eager resolving of this field is ever tried.) */
+
+ *exceptionptr = NULL;
+ return true; /* be lazy */
+ }
+
return false; /* exception */
+ }
+
+#ifdef ENABLE_VERIFIER
/* { the field reference has been resolved } */
declarer = fi->class;
- RESOLVE_ASSERT(declarer);
- RESOLVE_ASSERT(declarer->loaded && declarer->linked);
+ assert(declarer);
+ assert(declarer->loaded && declarer->linked);
#ifdef RESOLVE_VERBOSE
fprintf(stderr," checking static...\n");
#endif
/* check static */
+
if (((fi->flags & ACC_STATIC) != 0) != ((ref->flags & RESOLVE_STATIC) != 0)) {
/* a static field is accessed via an instance, or vice versa */
*exceptionptr = new_exception_message(string_java_lang_IncompatibleClassChangeError,
return false; /* exception */
}
- /* for non-static accesses we have to check the constraints on the instance type */
- if ((ref->flags & RESOLVE_STATIC) == 0) {
+ /* for non-static accesses we have to check the constraints on the */
+ /* instance type */
+
+ if (!(ref->flags & RESOLVE_STATIC)) {
#ifdef RESOLVE_VERBOSE
fprintf(stderr," checking instance types...\n");
#endif
if (!resolve_and_check_subtype_set(referer,ref->referermethod,
&(ref->instancetypes),
CLASSREF_OR_CLASSINFO(container),
- false,
- mode,
- resolveLinkageError,&checked))
+ false, mode, resolveLinkageError,
+ &checked))
{
return false; /* exception */
}
+
if (!checked)
return true; /* be lazy */
}
+#ifdef RESOLVE_VERBOSE
+ fprintf(stderr," checking instance types...done\n");
+#endif
+
fieldtyperef = ref->fieldref->parseddesc.fd->classref;
/* for PUT* instructions we have to check the constraints on the value type */
if (((ref->flags & RESOLVE_PUTFIELD) != 0) && fi->type == TYPE_ADR) {
- RESOLVE_ASSERT(fieldtyperef);
+#ifdef RESOLVE_VERBOSE
+ fprintf(stderr," checking value constraints...\n");
+#endif
+ assert(fieldtyperef);
if (!SUBTYPESET_IS_EMPTY(ref->valueconstraints)) {
/* check subtype constraints */
- if (!resolve_and_check_subtype_set(referer,ref->referermethod,
+ if (!resolve_and_check_subtype_set(referer, ref->referermethod,
&(ref->valueconstraints),
CLASSREF_OR_CLASSINFO(fieldtyperef),
- false,
- mode,
- resolveLinkageError,&checked))
+ false, mode, resolveLinkageError,
+ &checked))
{
return false; /* exception */
}
}
/* check access rights */
- if (!is_accessible_member(referer,declarer,fi->flags)) {
- *exceptionptr = new_exception_message(string_java_lang_IllegalAccessException,
- "field is not accessible XXX add message");
+#ifdef RESOLVE_VERBOSE
+ fprintf(stderr," checking access rights...\n");
+#endif
+ if (!access_is_accessible_member(referer,declarer,fi->flags)) {
+ int msglen;
+ char *message;
+
+ msglen = utf_strlen(declarer->name) + utf_strlen(fi->name) + utf_strlen(referer->name) + 100;
+ message = MNEW(char,msglen);
+ strcpy(message,"field is not accessible (");
+ utf_sprint_classname(message+strlen(message),declarer->name);
+ strcat(message,".");
+ utf_sprint(message+strlen(message),fi->name);
+ strcat(message," from ");
+ utf_sprint_classname(message+strlen(message),referer->name);
+ strcat(message,")");
+ *exceptionptr = new_exception_message(string_java_lang_IllegalAccessException,message);
+ MFREE(message,char,msglen);
return false; /* exception */
}
+#ifdef RESOLVE_VERBOSE
+ fprintf(stderr," checking access rights...done\n");
+ fprintf(stderr," declarer = ");
+ utf_fprint_classname(stderr,declarer->name); fputc('\n',stderr);
+ fprintf(stderr," referer = ");
+ utf_fprint_classname(stderr,referer->name); fputc('\n',stderr);
+#endif
/* check protected access */
if (((fi->flags & ACC_PROTECTED) != 0) && !SAME_PACKAGE(declarer,referer)) {
+#ifdef RESOLVE_VERBOSE
+ fprintf(stderr," checking protected access...\n");
+#endif
if (!resolve_and_check_subtype_set(referer,ref->referermethod,
&(ref->instancetypes),
CLASSREF_OR_CLASSINFO(referer),
- false,
- mode,
- resolveIllegalAccessError,&checked))
+ false, mode,
+ resolveIllegalAccessError, &checked))
{
return false; /* exception */
}
+
if (!checked)
return true; /* be lazy */
}
/* impose loading constraint on field type */
+
if (fi->type == TYPE_ADR) {
- RESOLVE_ASSERT(fieldtyperef);
- if (!classcache_add_constraint(declarer->classloader,referer->classloader,
- fieldtyperef->name))
- return false; /* exception */
+#ifdef RESOLVE_VERBOSE
+ fprintf(stderr," adding constraint...\n");
+#endif
+ assert(fieldtyperef);
+ if (!classcache_add_constraint(declarer->classloader,
+ referer->classloader,
+ fieldtyperef->name))
+ return false;
}
+#endif /* ENABLE_VERIFIER */
/* succeed */
+#ifdef RESOLVE_VERBOSE
+ fprintf(stderr," success.\n");
+#endif
*result = fi;
+
return true;
}
+/* resolve_field_eager *********************************************************
+
+ Resolve an unresolved field reference eagerly.
+
+ IN:
+ ref..............struct containing the reference
+
+ RETURN VALUE:
+ fieldinfo * to the field, or
+ NULL if an exception has been thrown
+
+*******************************************************************************/
+
+fieldinfo * resolve_field_eager(unresolved_field *ref)
+{
+ fieldinfo *fi;
+
+ if (!resolve_field(ref,resolveEager,&fi))
+ return NULL;
+
+ return fi;
+}
+
/******************************************************************************/
/* METHOD RESOLUTION */
/******************************************************************************/
-/* for documentation see resolve.h */
-bool
-resolve_method(unresolved_method *ref,
- resolve_mode_t mode,
- methodinfo **result)
+/* resolve_method **************************************************************
+
+ Resolve an unresolved method reference
+
+ IN:
+ ref..............struct containing the reference
+ mode.............mode of resolution:
+ resolveLazy...only resolve if it does not
+ require loading classes
+ resolveEager..load classes if necessary
+
+ OUT:
+ *result..........set to the result of resolution, or to NULL if
+ the reference has not been resolved
+ In the case of an exception, *result is
+ guaranteed to be set to NULL.
+
+ RETURN VALUE:
+ true.............everything ok
+ (*result may still be NULL for resolveLazy)
+ false............an exception has been thrown
+
+*******************************************************************************/
+
+bool resolve_method(unresolved_method *ref, resolve_mode_t mode, methodinfo **result)
{
classinfo *referer;
classinfo *container;
int i;
bool checked;
- RESOLVE_ASSERT(ref);
- RESOLVE_ASSERT(result);
- RESOLVE_ASSERT(mode == resolveLazy || mode == resolveEager);
+ assert(ref);
+ assert(result);
+ assert(mode == resolveLazy || mode == resolveEager);
#ifdef RESOLVE_VERBOSE
unresolved_method_debug_dump(ref,stderr);
/* the class containing the reference */
referer = ref->methodref->classref->referer;
- RESOLVE_ASSERT(referer);
+ assert(referer);
/* first we must resolve the class containg the method */
- if (!resolve_class(referer,ref->referermethod,
- ref->methodref->classref->name,mode,&container))
+ if (!resolve_class_from_name(referer,ref->referermethod,
+ ref->methodref->classref->name,mode,true,true,&container))
{
/* the class reference could not be resolved */
return false; /* exception */
if (!container)
return true; /* be lazy */
- RESOLVE_ASSERT(container);
+ assert(container);
+ assert(container->linked);
/* now we must find the declaration of the method in `container`
* or one of its superclasses */
- if ((container->flags & ACC_INTERFACE) != 0) {
+ if (container->flags & ACC_INTERFACE) {
mi = class_resolveinterfacemethod(container,
- ref->methodref->name,ref->methodref->descriptor,
- referer,true);
- }
- else {
+ ref->methodref->name,
+ ref->methodref->descriptor,
+ referer, true);
+
+ } else {
mi = class_resolveclassmethod(container,
- ref->methodref->name,ref->methodref->descriptor,
- referer,true);
+ ref->methodref->name,
+ ref->methodref->descriptor,
+ referer, true);
}
- if (!mi)
+
+ if (!mi) {
+ if (mode == resolveLazy) {
+ /* The method does not exist. But since we were called lazily, */
+ /* this error must not be reported now. (It will be reported */
+ /* if eager resolving of this method is ever tried.) */
+
+ *exceptionptr = NULL;
+ return true; /* be lazy */
+ }
+
return false; /* exception */ /* XXX set exceptionptr? */
+ }
+
+#ifdef ENABLE_VERIFIER
+#ifdef RESOLVE_VERBOSE
+ fprintf(stderr," flags: %02x\n",mi->flags);
+#endif
/* { the method reference has been resolved } */
+
declarer = mi->class;
- RESOLVE_ASSERT(declarer);
+ assert(declarer);
+ assert(referer->linked);
+
+ /* checks for INVOKESPECIAL: */
+ /* for <init> and methods of the current class we don't need any */
+ /* special checks. Otherwise we must verify that the called method */
+ /* belongs to a super class of the current class */
+ if (((ref->flags & RESOLVE_SPECIAL) != 0)
+ && referer != declarer
+ && mi->name != utf_init)
+ {
+ /* check that declarer is a super class of the current class */
+ if (!class_issubclass(referer,declarer)) {
+ *exceptionptr = new_verifyerror(ref->referermethod,
+ "INVOKESPECIAL calling non-super class method");
+ return false;
+ }
+
+ /* if the referer has ACC_SUPER set, we must do the special */
+ /* lookup starting with the direct super class of referer */
+ if ((referer->flags & ACC_SUPER) != 0) {
+ mi = class_resolvemethod(referer->super.cls,
+ ref->methodref->name,
+ ref->methodref->descriptor);
+ if (!mi) {
+ /* the spec calls for an AbstractMethodError in this case */
+ *exceptionptr = new_exception(string_java_lang_AbstractMethodError);
+ return false;
+ }
+ declarer = mi->class;
+ }
+ }
/* check static */
+
if (((mi->flags & ACC_STATIC) != 0) != ((ref->flags & RESOLVE_STATIC) != 0)) {
/* a static method is accessed via an instance, or vice versa */
- *exceptionptr = new_exception_message(string_java_lang_IncompatibleClassChangeError,
+ *exceptionptr =
+ new_exception_message(string_java_lang_IncompatibleClassChangeError,
(mi->flags & ACC_STATIC) ? "static method called via instance"
: "instance method called without instance");
- return false; /* exception */
+ return false;
}
- /* for non-static methods we have to check the constraints on the instance type */
- if ((ref->flags & RESOLVE_STATIC) == 0) {
+ /* have the method params already been parsed? no, do it. */
+
+ if (!mi->parseddesc->params)
+ if (!descriptor_params_from_paramtypes(mi->parseddesc, mi->flags))
+ return false;
+
+ /* for non-static methods we have to check the constraints on the */
+ /* instance type */
+
+ if (!(ref->flags & RESOLVE_STATIC)) {
if (!resolve_and_check_subtype_set(referer,ref->referermethod,
&(ref->instancetypes),
CLASSREF_OR_CLASSINFO(container),
}
/* check subtype constraints for TYPE_ADR parameters */
- RESOLVE_ASSERT((mi->paramcount-instancecount) == ref->methodref->parseddesc.md->paramcount);
- paramtypes = ref->methodref->parseddesc.md->paramtypes;
+
+ assert(mi->parseddesc->paramcount == ref->methodref->parseddesc.md->paramcount);
+ paramtypes = mi->parseddesc->paramtypes;
- for (i=0; i<(mi->paramcount-instancecount); ++i) {
- if (mi->paramtypes[instancecount + i] == TYPE_ADR) {
- RESOLVE_ASSERT(paramtypes[i].type == TYPE_ADR);
+ for (i = 0; i < mi->parseddesc->paramcount-instancecount; i++) {
+ if (paramtypes[i+instancecount].type == TYPE_ADR) {
if (ref->paramconstraints) {
if (!resolve_and_check_subtype_set(referer,ref->referermethod,
ref->paramconstraints + i,
- CLASSREF_OR_CLASSINFO(paramtypes[i].classref),
+ CLASSREF_OR_CLASSINFO(paramtypes[i+instancecount].classref),
false,
mode,
resolveLinkageError,&checked))
}
/* check access rights */
- if (!is_accessible_member(referer,declarer,mi->flags)) {
- *exceptionptr = new_exception_message(string_java_lang_IllegalAccessException,
- "method is not accessible XXX add message");
+
+ if (!access_is_accessible_member(referer,declarer,mi->flags)) {
+ int msglen;
+ char *message;
+
+ msglen = utf_strlen(declarer->name) + utf_strlen(mi->name) +
+ utf_strlen(mi->descriptor) + utf_strlen(referer->name) + 100;
+ message = MNEW(char,msglen);
+ strcpy(message,"method is not accessible (");
+ utf_sprint_classname(message+strlen(message),declarer->name);
+ strcat(message,".");
+ utf_sprint(message+strlen(message),mi->name);
+ utf_sprint(message+strlen(message),mi->descriptor);
+ strcat(message," from ");
+ utf_sprint_classname(message+strlen(message),referer->name);
+ strcat(message,")");
+ *exceptionptr = new_exception_message(string_java_lang_IllegalAccessException,message);
+ MFREE(message,char,msglen);
return false; /* exception */
}
/* check protected access */
- if (((mi->flags & ACC_PROTECTED) != 0) && !SAME_PACKAGE(declarer,referer)) {
- /* XXX do we also need to check (referer subclass_of declarer)? */
+
+ if (((mi->flags & ACC_PROTECTED) != 0) && !SAME_PACKAGE(declarer,referer))
+ {
if (!resolve_and_check_subtype_set(referer,ref->referermethod,
&(ref->instancetypes),
CLASSREF_OR_CLASSINFO(referer),
}
/* impose loading constraints on parameters (including instance) */
- paramtypes = ref->methodref->parseddesc.md->paramtypes - instancecount;
- for (i=0; i<mi->paramcount; ++i) {
- if (mi->paramtypes[i] == TYPE_ADR) {
+
+ paramtypes = mi->parseddesc->paramtypes;
+
+ for (i = 0; i < mi->parseddesc->paramcount; i++) {
+ if (i < instancecount || paramtypes[i].type == TYPE_ADR) {
utf *name;
if (i < instancecount)
else
name = paramtypes[i].classref->name;
- if (!classcache_add_constraint(referer->classloader,declarer->classloader,name))
+ if (!classcache_add_constraint(referer->classloader,
+ declarer->classloader, name))
return false; /* exception */
}
}
/* impose loading constraing onto return type */
+
if (ref->methodref->parseddesc.md->returntype.type == TYPE_ADR) {
if (!classcache_add_constraint(referer->classloader,declarer->classloader,
ref->methodref->parseddesc.md->returntype.classref->name))
return false; /* exception */
}
+#endif /* ENABLE_VERIFIER */
+
/* succeed */
*result = mi;
return true;
}
+/* resolve_method_eager ********************************************************
+
+ Resolve an unresolved method reference eagerly.
+
+ IN:
+ ref..............struct containing the reference
+
+ RETURN VALUE:
+ methodinfo * to the method, or
+ NULL if an exception has been thrown
+
+*******************************************************************************/
+
+methodinfo * resolve_method_eager(unresolved_method *ref)
+{
+ methodinfo *mi;
+
+ if (!resolve_method(ref,resolveEager,&mi))
+ return NULL;
+
+ return mi;
+}
+
/******************************************************************************/
/* CREATING THE DATA STRUCTURES */
/******************************************************************************/
-static bool
-unresolved_subtype_set_from_typeinfo(classinfo *referer,methodinfo *refmethod,
- unresolved_subtype_set *stset,typeinfo *tinfo,
- constant_classref *declaredtype)
+#ifdef ENABLE_VERIFIER
+static bool unresolved_subtype_set_from_typeinfo(classinfo *referer,
+ methodinfo *refmethod,
+ unresolved_subtype_set *stset,
+ typeinfo *tinfo,
+ constant_classref *declaredtype)
{
int count;
int i;
- RESOLVE_ASSERT(stset);
- RESOLVE_ASSERT(tinfo);
+ assert(stset);
+ assert(tinfo);
#ifdef RESOLVE_VERBOSE
fprintf(stderr,"unresolved_subtype_set_from_typeinfo\n");
#ifdef TYPEINFO_DEBUG
- /*typeinfo_print(stderr,tinfo,4);*/
- fprintf(stderr,"\n");
+ typeinfo_print(stderr,tinfo,4);
#endif
fprintf(stderr," declared type:");utf_fprint(stderr,declaredtype->name);
fprintf(stderr,"\n");
count = tinfo->merged->count;
stset->subtyperefs = MNEW(classref_or_classinfo,count + 1);
for (i=0; i<count; ++i) {
- stset->subtyperefs[i] = tinfo->merged->list[i];
+ classref_or_classinfo c = tinfo->merged->list[i];
+ if (tinfo->dimension > 0) {
+ /* a merge of array types */
+ /* the merged list contains the possible _element_ types, */
+ /* so we have to create array types with these elements. */
+ if (IS_CLASSREF(c)) {
+ c.ref = class_get_classref_multiarray_of(tinfo->dimension,c.ref);
+ }
+ else {
+ c.cls = class_multiarray_of(tinfo->dimension,c.cls,false);
+ }
+ }
+ stset->subtyperefs[i] = c;
}
stset->subtyperefs[count].any = NULL; /* terminate */
}
? tinfo->typeclass.ref->name
: tinfo->typeclass.cls->name) == declaredtype->name)
{
+ /* the class names are the same */
+ /* equality is guaranteed by the loading constraints */
goto empty_set;
}
else {
UNRESOLVED_SUBTYPE_SET_EMTPY(*stset);
return true;
}
+#endif /* ENABLE_VERIFIER */
+
+/* create_unresolved_class *****************************************************
+
+ Create an unresolved_class struct for the given class reference
+
+ IN:
+ refmethod........the method triggering the resolution (if any)
+ classref.........the class reference
+ valuetype........value type to check against the resolved class
+ may be NULL, if no typeinfo is available
+
+ RETURN VALUE:
+ a pointer to a new unresolved_class struct, or
+ NULL if an exception has been thrown
+
+*******************************************************************************/
+
+#ifdef ENABLE_VERIFIER
+unresolved_class * create_unresolved_class(methodinfo *refmethod,
+ constant_classref *classref,
+ typeinfo *valuetype)
+{
+ unresolved_class *ref;
+
+#ifdef RESOLVE_VERBOSE
+ fprintf(stderr,"create_unresolved_class\n");
+ fprintf(stderr," referer: ");utf_fprint(stderr,classref->referer->name);fputc('\n',stderr);
+ if (refmethod) {
+ fprintf(stderr," rmethod: ");utf_fprint(stderr,refmethod->name);fputc('\n',stderr);
+ fprintf(stderr," rmdesc : ");utf_fprint(stderr,refmethod->descriptor);fputc('\n',stderr);
+ }
+ fprintf(stderr," name : ");utf_fprint(stderr,classref->name);fputc('\n',stderr);
+#endif
+
+ ref = NEW(unresolved_class);
+ ref->classref = classref;
+ ref->referermethod = refmethod;
+
+ if (valuetype) {
+ if (!unresolved_subtype_set_from_typeinfo(classref->referer,refmethod,
+ &(ref->subtypeconstraints),valuetype,classref))
+ return NULL;
+ }
+ else {
+ UNRESOLVED_SUBTYPE_SET_EMTPY(ref->subtypeconstraints);
+ }
+
+ return ref;
+}
+#endif /* ENABLE_VERIFIER */
+
+/* create_unresolved_field *****************************************************
+
+ Create an unresolved_field struct for the given field access instruction
+
+ IN:
+ referer..........the class containing the reference
+ refmethod........the method triggering the resolution (if any)
+ iptr.............the {GET,PUT}{FIELD,STATIC}{,CONST} instruction
+
+ RETURN VALUE:
+ a pointer to a new unresolved_field struct, or
+ NULL if an exception has been thrown
+
+*******************************************************************************/
-unresolved_field *
-create_unresolved_field(classinfo *referer,methodinfo *refmethod,
- instruction *iptr,
- stackelement *stack)
+unresolved_field * create_unresolved_field(classinfo *referer, methodinfo *refmethod,
+ instruction *iptr)
{
unresolved_field *ref;
constant_FMIref *fieldref = NULL;
- stackelement *instanceslot = NULL;
- int type;
- typeinfo tinfo;
- typeinfo *tip = NULL;
- typedesc *fd;
#ifdef RESOLVE_VERBOSE
fprintf(stderr,"create_unresolved_field\n");
ref = NEW(unresolved_field);
ref->flags = 0;
ref->referermethod = refmethod;
+ UNRESOLVED_SUBTYPE_SET_EMTPY(ref->valueconstraints);
switch (iptr[0].opc) {
case ICMD_PUTFIELD:
ref->flags |= RESOLVE_PUTFIELD;
- instanceslot = stack->prev;
- tip = &(stack->typeinfo);
fieldref = (constant_FMIref *) iptr[0].val.a;
break;
case ICMD_PUTFIELDCONST:
ref->flags |= RESOLVE_PUTFIELD;
- instanceslot = stack;
- fieldref = INSTRUCTION_PUTCONST_FIELDREF(iptr);
+ fieldref = (constant_FMIref *) iptr[1].val.a;
break;
case ICMD_PUTSTATIC:
ref->flags |= RESOLVE_PUTFIELD | RESOLVE_STATIC;
fieldref = (constant_FMIref *) iptr[0].val.a;
- tip = &(stack->typeinfo);
break;
case ICMD_PUTSTATICCONST:
ref->flags |= RESOLVE_PUTFIELD | RESOLVE_STATIC;
- fieldref = INSTRUCTION_PUTCONST_FIELDREF(iptr);
+ fieldref = (constant_FMIref *) iptr[1].val.a;
break;
case ICMD_GETFIELD:
- instanceslot = stack;
fieldref = (constant_FMIref *) iptr[0].val.a;
break;
break;
}
- RESOLVE_ASSERT(fieldref);
- RESOLVE_ASSERT(instanceslot || ((ref->flags & RESOLVE_STATIC) != 0));
- fd = fieldref->parseddesc.fd;
- RESOLVE_ASSERT(fd);
+ assert(fieldref);
#ifdef RESOLVE_VERBOSE
fprintf(stderr," class : ");utf_fprint(stderr,fieldref->classref->name);fputc('\n',stderr);
#endif
ref->fieldref = fieldref;
+
+ return ref;
+}
+
+/* constrain_unresolved_field **************************************************
+
+ Record subtype constraints for a field access.
+
+ IN:
+ ref..............the unresolved_field structure of the access
+ referer..........the class containing the reference
+ refmethod........the method triggering the resolution (if any)
+ iptr.............the {GET,PUT}{FIELD,STATIC}{,CONST} instruction
+ stack............the input stack of the instruction
+
+ RETURN VALUE:
+ true.............everything ok
+ false............an exception has been thrown
+
+*******************************************************************************/
+
+#ifdef ENABLE_VERIFIER
+bool constrain_unresolved_field(unresolved_field *ref,
+ classinfo *referer, methodinfo *refmethod,
+ instruction *iptr,
+ stackelement *stack)
+{
+ constant_FMIref *fieldref;
+ stackelement *instanceslot = NULL;
+ int type;
+ typeinfo tinfo;
+ typeinfo *tip = NULL;
+ typedesc *fd;
+
+ assert(ref);
+
+ fieldref = ref->fieldref;
+ assert(fieldref);
+
+#ifdef RESOLVE_VERBOSE
+ fprintf(stderr,"constrain_unresolved_field\n");
+ fprintf(stderr," referer: ");utf_fprint(stderr,referer->name);fputc('\n',stderr);
+ fprintf(stderr," rmethod: ");utf_fprint(stderr,refmethod->name);fputc('\n',stderr);
+ fprintf(stderr," rmdesc : ");utf_fprint(stderr,refmethod->descriptor);fputc('\n',stderr);
+ fprintf(stderr," class : ");utf_fprint(stderr,fieldref->classref->name);fputc('\n',stderr);
+ fprintf(stderr," name : ");utf_fprint(stderr,fieldref->name);fputc('\n',stderr);
+ fprintf(stderr," desc : ");utf_fprint(stderr,fieldref->descriptor);fputc('\n',stderr);
+ fprintf(stderr," type : ");descriptor_debug_print_typedesc(stderr,fieldref->parseddesc.fd);
+ fputc('\n',stderr);
+ /*fprintf(stderr," opcode : %d %s\n",iptr[0].opc,icmd_names[iptr[0].opc]);*/
+#endif
+
+ switch (iptr[0].opc) {
+ case ICMD_PUTFIELD:
+ instanceslot = stack->prev;
+ tip = &(stack->typeinfo);
+ break;
+
+ case ICMD_PUTFIELDCONST:
+ instanceslot = stack;
+ break;
+
+ case ICMD_PUTSTATIC:
+ tip = &(stack->typeinfo);
+ break;
+
+ case ICMD_GETFIELD:
+ instanceslot = stack;
+ break;
+ }
+ assert(instanceslot || ((ref->flags & RESOLVE_STATIC) != 0));
+ fd = fieldref->parseddesc.fd;
+ assert(fd);
+
/* record subtype constraints for the instance type, if any */
if (instanceslot) {
typeinfo *insttip;
- RESOLVE_ASSERT(instanceslot->type == TYPE_ADR);
+
+ /* The instanceslot must contain a reference to a non-array type */
+ if (!TYPEINFO_IS_REFERENCE(instanceslot->typeinfo)) {
+ *exceptionptr = new_verifyerror(refmethod, "illegal instruction: field access on non-reference");
+ return false;
+ }
+ if (TYPEINFO_IS_ARRAY(instanceslot->typeinfo)) {
+ *exceptionptr = new_verifyerror(refmethod, "illegal instruction: field access on array");
+ return false;
+ }
if (((ref->flags & RESOLVE_PUTFIELD) != 0) &&
TYPEINFO_IS_NEWOBJECT(instanceslot->typeinfo))
- { /* XXX clean up */
+ {
+ /* The instruction writes a field in an uninitialized object. */
+ /* This is only allowed when a field of an uninitialized 'this' object is */
+ /* written inside an initialization method */
+
+ classinfo *initclass;
instruction *ins = (instruction*)TYPEINFO_NEWOBJECT_INSTRUCTION(instanceslot->typeinfo);
- classinfo *initclass = (ins) ? (classinfo*)ins[-1].val.a
- : refmethod->class; /* XXX classrefs */
- RESOLVE_ASSERT(initclass->loaded && initclass->linked);
- TYPEINFO_INIT_CLASSINFO(tinfo,initclass);
+
+ if (ins != NULL) {
+ *exceptionptr = new_verifyerror(refmethod,"accessing field of uninitialized object");
+ return false;
+ }
+ /* XXX check that class of field == refmethod->class */
+ initclass = refmethod->class; /* XXX classrefs */
+ assert(initclass->loaded && initclass->linked);
+ typeinfo_init_classinfo(&tinfo,initclass);
insttip = &tinfo;
}
else {
}
if (!unresolved_subtype_set_from_typeinfo(referer,refmethod,
&(ref->instancetypes),insttip,fieldref->classref))
- return NULL;
+ return false;
}
else {
UNRESOLVED_SUBTYPE_SET_EMTPY(ref->instancetypes);
/* we have a PUTSTATICCONST or PUTFIELDCONST with TYPE_ADR */
tip = &tinfo;
if (INSTRUCTION_PUTCONST_VALUE_ADR(iptr)) {
- TYPEINFO_INIT_CLASSINFO(tinfo,class_java_lang_String); /* XXX assert loaded & linked? */
+ assert(class_java_lang_String);
+ assert(class_java_lang_String->loaded);
+ assert(class_java_lang_String->linked);
+ typeinfo_init_classinfo(&tinfo,class_java_lang_String);
}
else
TYPEINFO_INIT_NULLTYPE(tinfo);
}
if (!unresolved_subtype_set_from_typeinfo(referer,refmethod,
&(ref->valueconstraints),tip,fieldref->parseddesc.fd->classref))
- return NULL;
+ return false;
}
else {
UNRESOLVED_SUBTYPE_SET_EMTPY(ref->valueconstraints);
}
- return ref;
+ return true;
}
+#endif /* ENABLE_VERIFIER */
+
+/* create_unresolved_method ****************************************************
+
+ Create an unresolved_method struct for the given method invocation
+
+ IN:
+ referer..........the class containing the reference
+ refmethod........the method triggering the resolution (if any)
+ iptr.............the INVOKE* instruction
+
+ RETURN VALUE:
+ a pointer to a new unresolved_method struct, or
+ NULL if an exception has been thrown
-unresolved_method *
-create_unresolved_method(classinfo *referer,methodinfo *refmethod,
- instruction *iptr,
- stackelement *stack)
+*******************************************************************************/
+
+unresolved_method * create_unresolved_method(classinfo *referer, methodinfo *refmethod,
+ instruction *iptr)
{
unresolved_method *ref;
constant_FMIref *methodref;
- stackelement *instanceslot = NULL;
- stackelement *param;
- methoddesc *md;
- typeinfo tinfo;
- int i,j;
- int type;
+ bool staticmethod;
methodref = (constant_FMIref *) iptr[0].val.a;
- RESOLVE_ASSERT(methodref);
- md = methodref->parseddesc.md;
- RESOLVE_ASSERT(md);
+ assert(methodref);
+ staticmethod = (iptr[0].opc == ICMD_INVOKESTATIC);
#ifdef RESOLVE_VERBOSE
fprintf(stderr,"create_unresolved_method\n");
/*fprintf(stderr," opcode : %d %s\n",iptr[0].opc,icmd_names[iptr[0].opc]);*/
#endif
+ /* allocate params if necessary */
+ if (!methodref->parseddesc.md->params)
+ if (!descriptor_params_from_paramtypes(methodref->parseddesc.md,
+ (staticmethod) ? ACC_STATIC : ACC_NONE))
+ return NULL;
+
+ /* create the data structure */
ref = NEW(unresolved_method);
- ref->flags = 0;
+ ref->flags = ((staticmethod) ? RESOLVE_STATIC : 0)
+ | ((iptr[0].opc == ICMD_INVOKESPECIAL) ? RESOLVE_SPECIAL : 0);
ref->referermethod = refmethod;
ref->methodref = methodref;
ref->paramconstraints = NULL;
+ UNRESOLVED_SUBTYPE_SET_EMTPY(ref->instancetypes);
- switch (iptr[0].opc) {
- case ICMD_INVOKESTATIC:
- ref->flags |= RESOLVE_STATIC;
- break;
- case ICMD_INVOKEVIRTUAL:
- case ICMD_INVOKESPECIAL:
- case ICMD_INVOKEINTERFACE:
- break;
- default:
- RESOLVE_ASSERT(false);
- }
+ return ref;
+}
+
+/* constrain_unresolved_method *************************************************
+
+ Record subtype constraints for the arguments of a method call.
+
+ IN:
+ ref..............the unresolved_method structure of the call
+ referer..........the class containing the reference
+ refmethod........the method triggering the resolution (if any)
+ iptr.............the INVOKE* instruction
+ stack............the input stack of the instruction
+
+ RETURN VALUE:
+ true.............everything ok
+ false............an exception has been thrown
+
+*******************************************************************************/
+
+#ifdef ENABLE_VERIFIER
+bool constrain_unresolved_method(unresolved_method *ref,
+ classinfo *referer, methodinfo *refmethod,
+ instruction *iptr,
+ stackelement *stack)
+{
+ constant_FMIref *methodref;
+ stackelement *instanceslot = NULL;
+ stackelement *param;
+ methoddesc *md;
+ typeinfo tinfo;
+ int i,j;
+ int type;
+ int instancecount;
+
+ assert(ref);
+ methodref = ref->methodref;
+ assert(methodref);
+ md = methodref->parseddesc.md;
+ assert(md);
+ assert(md->params != NULL);
+
+#ifdef RESOLVE_VERBOSE
+ fprintf(stderr,"constrain_unresolved_method\n");
+ fprintf(stderr," referer: ");utf_fprint(stderr,referer->name);fputc('\n',stderr);
+ fprintf(stderr," rmethod: ");utf_fprint(stderr,refmethod->name);fputc('\n',stderr);
+ fprintf(stderr," rmdesc : ");utf_fprint(stderr,refmethod->descriptor);fputc('\n',stderr);
+ fprintf(stderr," class : ");utf_fprint(stderr,methodref->classref->name);fputc('\n',stderr);
+ fprintf(stderr," name : ");utf_fprint(stderr,methodref->name);fputc('\n',stderr);
+ fprintf(stderr," desc : ");utf_fprint(stderr,methodref->descriptor);fputc('\n',stderr);
+ /*fprintf(stderr," opcode : %d %s\n",iptr[0].opc,icmd_names[iptr[0].opc]);*/
+#endif
if ((ref->flags & RESOLVE_STATIC) == 0) {
/* find the instance slot under all the parameter slots on the stack */
instanceslot = stack;
- for (i=0; i<md->paramcount; ++i)
+ for (i=1; i<md->paramcount; ++i)
instanceslot = instanceslot->prev;
+ instancecount = 1;
+ }
+ else {
+ instancecount = 0;
}
- RESOLVE_ASSERT(instanceslot || ((ref->flags & RESOLVE_STATIC) != 0));
+ assert((instanceslot && instancecount==1) || ((ref->flags & RESOLVE_STATIC) != 0));
/* record subtype constraints for the instance type, if any */
if (instanceslot) {
typeinfo *tip;
- RESOLVE_ASSERT(instanceslot->type == TYPE_ADR);
+ assert(instanceslot->type == TYPE_ADR);
if (iptr[0].opc == ICMD_INVOKESPECIAL &&
TYPEINFO_IS_NEWOBJECT(instanceslot->typeinfo))
{ /* XXX clean up */
instruction *ins = (instruction*)TYPEINFO_NEWOBJECT_INSTRUCTION(instanceslot->typeinfo);
- classinfo *initclass = (ins) ? (classinfo*)ins[-1].val.a
- : refmethod->class; /* XXX classrefs */
- RESOLVE_ASSERT(initclass->loaded && initclass->linked);
- TYPEINFO_INIT_CLASSINFO(tinfo,initclass);
+ classref_or_classinfo initclass = (ins) ? CLASSREF_OR_CLASSINFO(ins[-1].target)
+ : CLASSREF_OR_CLASSINFO(refmethod->class);
tip = &tinfo;
+ if (!typeinfo_init_class(tip,initclass))
+ return false;
}
else {
tip = &(instanceslot->typeinfo);
}
if (!unresolved_subtype_set_from_typeinfo(referer,refmethod,
&(ref->instancetypes),tip,methodref->classref))
- return NULL;
- }
- else {
- UNRESOLVED_SUBTYPE_SET_EMTPY(ref->instancetypes);
+ return false;
}
/* record subtype constraints for the parameter types, if any */
param = stack;
- for (i=md->paramcount-1; i>=0; --i, param=param->prev) {
- type = md->paramtypes[i].type;
-
- RESOLVE_ASSERT(param);
- RESOLVE_ASSERT(type == param->type);
-
+ for (i=md->paramcount-1-instancecount; i>=0; --i, param=param->prev) {
+ type = md->paramtypes[i+instancecount].type;
+
+ assert(param);
+ assert(type == param->type);
+
if (type == TYPE_ADR) {
if (!ref->paramconstraints) {
ref->paramconstraints = MNEW(unresolved_subtype_set,md->paramcount);
- for (j=md->paramcount-1; j>i; --j)
+ for (j=md->paramcount-1-instancecount; j>i; --j)
UNRESOLVED_SUBTYPE_SET_EMTPY(ref->paramconstraints[j]);
}
- RESOLVE_ASSERT(ref->paramconstraints);
+ assert(ref->paramconstraints);
if (!unresolved_subtype_set_from_typeinfo(referer,refmethod,
ref->paramconstraints + i,&(param->typeinfo),
- md->paramtypes[i].classref))
- return NULL;
+ md->paramtypes[i+instancecount].classref))
+ return false;
}
else {
if (ref->paramconstraints)
}
}
- return ref;
+ return true;
}
+#endif /* ENABLE_VERIFIER */
/******************************************************************************/
/* FREEING MEMORY */
/******************************************************************************/
-inline static void
-unresolved_subtype_set_free_list(classref_or_classinfo *list)
+#ifdef ENABLE_VERIFIER
+inline static void unresolved_subtype_set_free_list(classref_or_classinfo *list)
{
if (list) {
classref_or_classinfo *p = list;
MFREE(list,classref_or_classinfo,(p - list));
}
}
+#endif /* ENABLE_VERIFIER */
+
+/* unresolved_class_free *******************************************************
+
+ Free the memory used by an unresolved_class
+
+ IN:
+ ref..............the unresolved_class
+
+*******************************************************************************/
+
+void unresolved_class_free(unresolved_class *ref)
+{
+ assert(ref);
+
+#ifdef ENABLE_VERIFIER
+ unresolved_subtype_set_free_list(ref->subtypeconstraints.subtyperefs);
+#endif
+ FREE(ref,unresolved_class);
+}
/* unresolved_field_free *******************************************************
*******************************************************************************/
-void
-unresolved_field_free(unresolved_field *ref)
+void unresolved_field_free(unresolved_field *ref)
{
- RESOLVE_ASSERT(ref);
+ assert(ref);
+#ifdef ENABLE_VERIFIER
unresolved_subtype_set_free_list(ref->instancetypes.subtyperefs);
unresolved_subtype_set_free_list(ref->valueconstraints.subtyperefs);
+#endif
FREE(ref,unresolved_field);
}
*******************************************************************************/
-void
-unresolved_method_free(unresolved_method *ref)
+void unresolved_method_free(unresolved_method *ref)
{
- RESOLVE_ASSERT(ref);
+ assert(ref);
+#ifdef ENABLE_VERIFIER
unresolved_subtype_set_free_list(ref->instancetypes.subtyperefs);
if (ref->paramconstraints) {
int i;
unresolved_subtype_set_free_list(ref->paramconstraints[i].subtyperefs);
MFREE(ref->paramconstraints,unresolved_subtype_set,count);
}
+#endif
FREE(ref,unresolved_method);
}
+#ifndef NDEBUG
/******************************************************************************/
/* DEBUG DUMPS */
/******************************************************************************/
*******************************************************************************/
-void
-unresolved_subtype_set_debug_dump(unresolved_subtype_set *stset,FILE *file)
+void unresolved_subtype_set_debug_dump(unresolved_subtype_set *stset,FILE *file)
{
classref_or_classinfo *p;
}
}
+/* unresolved_class_debug_dump *************************************************
+
+ Print debug info for unresolved_class to stream
+
+ IN:
+ ref..............the unresolved_class
+ file.............the stream
+
+*******************************************************************************/
+
+void unresolved_class_debug_dump(unresolved_class *ref,FILE *file)
+{
+ fprintf(file,"unresolved_class(%p):\n",(void *)ref);
+ if (ref) {
+ fprintf(file," referer : ");
+ utf_fprint(file,ref->classref->referer->name); fputc('\n',file);
+ fprintf(file," refmethod : ");
+ utf_fprint(file,ref->referermethod->name); fputc('\n',file);
+ fprintf(file," refmethodd: ");
+ utf_fprint(file,ref->referermethod->descriptor); fputc('\n',file);
+ fprintf(file," classname : ");
+ utf_fprint(file,ref->classref->name); fputc('\n',file);
+ fprintf(file," subtypeconstraints:\n");
+ unresolved_subtype_set_debug_dump(&(ref->subtypeconstraints),file);
+ }
+}
+
/* unresolved_field_debug_dump *************************************************
Print debug info for unresolved_field to stream
*******************************************************************************/
-void
-unresolved_field_debug_dump(unresolved_field *ref,FILE *file)
+void unresolved_field_debug_dump(unresolved_field *ref,FILE *file)
{
fprintf(file,"unresolved_field(%p):\n",(void *)ref);
if (ref) {
fprintf(file," referer : ");
utf_fprint(file,ref->fieldref->classref->referer->name); fputc('\n',file);
- fprintf(file," refmethod : ");
+ fprintf(file," refmethod : ");
utf_fprint(file,ref->referermethod->name); fputc('\n',file);
- fprintf(file," refmethodd : ");
+ fprintf(file," refmethodd: ");
utf_fprint(file,ref->referermethod->descriptor); fputc('\n',file);
fprintf(file," classname : ");
utf_fprint(file,ref->fieldref->classref->name); fputc('\n',file);
*******************************************************************************/
-void
-unresolved_method_debug_dump(unresolved_method *ref,FILE *file)
+void unresolved_method_debug_dump(unresolved_method *ref,FILE *file)
{
int i;
if (ref) {
fprintf(file," referer : ");
utf_fprint(file,ref->methodref->classref->referer->name); fputc('\n',file);
- fprintf(file," refmethod : ");
+ fprintf(file," refmethod : ");
utf_fprint(file,ref->referermethod->name); fputc('\n',file);
- fprintf(file," refmethodd : ");
+ fprintf(file," refmethodd: ");
utf_fprint(file,ref->referermethod->descriptor); fputc('\n',file);
fprintf(file," classname : ");
utf_fprint(file,ref->methodref->classref->name); fputc('\n',file);
}
}
}
+#endif
/*
* These are local overrides for various environment variables in Emacs.