X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fresolve.c;h=f76d7c07b82eef56a46bcf47f5089b9064142942;hb=1e162837cea0a838d3f857fd23a29544a2eabf74;hp=e7d25fd64579ff2a36b461cde6f0cddd8e8dffe2;hpb=9807e09dbdae71b290c33e2472f38df575a12996;p=cacao.git diff --git a/src/vm/resolve.c b/src/vm/resolve.c index e7d25fd64..f76d7c07b 100644 --- a/src/vm/resolve.c +++ b/src/vm/resolve.c @@ -28,7 +28,7 @@ Changes: Christan Thalinger - $Id: resolve.c 4758 2006-04-12 17:51:10Z edwin $ + $Id: resolve.c 5053 2006-06-28 19:11:20Z twisti $ */ @@ -46,6 +46,7 @@ #include "vm/global.h" #include "vm/linker.h" #include "vm/loader.h" +#include "vm/options.h" #include "vm/stringlocal.h" #include "vm/jit/jit.h" #include "vm/jit/verify/typeinfo.h" @@ -116,9 +117,9 @@ bool resolve_class_from_name(classinfo *referer, #ifdef RESOLVE_VERBOSE fprintf(stderr,"resolve_class_from_name("); - utf_fprint(stderr,referer->name); + utf_fprint_printable_ascii(stderr,referer->name); fprintf(stderr,",%p,",referer->classloader); - utf_fprint(stderr,classname); + utf_fprint_printable_ascii(stderr,classname); fprintf(stderr,",%d,%d)\n",(int)checkaccess,(int)link); #endif @@ -192,14 +193,14 @@ bool resolve_class_from_name(classinfo *referer, 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); + 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); return false; /* exception */ } @@ -304,7 +305,7 @@ bool resolve_classref_or_classinfo(methodinfo *refmethod, #ifdef RESOLVE_VERBOSE fprintf(stderr,"resolve_classref_or_classinfo("); - utf_fprint(stderr,(IS_CLASSREF(cls)) ? cls.ref->name : cls.cls->name); + utf_fprint_printable_ascii(stderr,(IS_CLASSREF(cls)) ? cls.ref->name : cls.cls->name); fprintf(stderr,",%i,%i,%i)\n",mode,(int)checkaccess,(int)link); #endif @@ -368,7 +369,7 @@ bool resolve_classref_or_classinfo(methodinfo *refmethod, false............an exception has been thrown NOTE: - This function always resolved eagerly. + This function always resolves eagerly. *******************************************************************************/ @@ -407,7 +408,7 @@ bool resolve_class_from_typedesc(typedesc *d, bool checkaccess, bool link, class assert(!link || (cls->state & CLASS_LINKED)); #ifdef RESOLVE_VERBOSE - fprintf(stderr," result = ");utf_fprint(stderr,cls->name);fprintf(stderr,"\n"); + fprintf(stderr," result = ");utf_fprint_printable_ascii(stderr,cls->name);fprintf(stderr,"\n"); #endif *result = cls; @@ -418,21 +419,268 @@ bool resolve_class_from_typedesc(typedesc *d, bool checkaccess, bool link, class /* SUBTYPE SET CHECKS */ /******************************************************************************/ -#ifdef ENABLE_VERIFIER +/* resolve_subtype_check ******************************************************* + + Resolve the given types lazily and perform a subtype check + + IN: + refmethod........the method triggering the resolution + subtype..........checked to be a subtype of supertype + supertype........the super type to check agaings + 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 are not checked. + + RETURN VALUE: + resolveSucceeded.....the check succeeded + resolveDeferred......the check could not be performed due to + unresolved types. (This can only happen for + mode == resolveLazy.) + resolveFailed........the check failed, an exception has been thrown. + + NOTE: + The types are resolved first, so any + exception which may occurr during resolution may + be thrown by this function. + +*******************************************************************************/ + +#if defined(ENABLE_VERIFIER) +static resolve_result_t resolve_subtype_check(methodinfo *refmethod, + classref_or_classinfo subtype, + classref_or_classinfo supertype, + resolve_mode_t mode, + resolve_err_t error) +{ + classinfo *subclass; + typeinfo subti; + typecheck_result r; + + assert(refmethod); + assert(subtype.any); + assert(supertype.any); + assert(mode == resolveLazy || mode == resolveEager); + assert(error == resolveLinkageError || error == resolveIllegalAccessError); + + /* resolve the subtype */ + + if (!resolve_classref_or_classinfo(refmethod,subtype,mode,false,true,&subclass)) { + /* 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; + return resolveSucceeded; + } + if (!subclass) + return resolveDeferred; /* be lazy */ + + assert(subclass->state & CLASS_LINKED); + + /* do not check access to protected members of arrays */ + + if (error == resolveIllegalAccessError && subclass->name->text[0] == '[') { + return resolveSucceeded; + } + + /* perform the subtype check */ + + typeinfo_init_classinfo(&subti,subclass); +check_again: + r = typeinfo_is_assignable_to_class(&subti,supertype); + if (r == typecheck_FAIL) + return resolveFailed; /* failed, exception is already set */ + + if (r == typecheck_MAYBE) { + assert(IS_CLASSREF(supertype)); + if (mode == resolveEager) { + if (!resolve_classref_or_classinfo(refmethod,supertype, + resolveEager,false,true, + &supertype.cls)) + { + return resolveFailed; + } + assert(supertype.cls); + goto check_again; + } + + return resolveDeferred; /* be lazy */ + } + + if (!r) { + /* sub class relationship is false */ + + char *message; + int msglen; + + 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, ")"); + if (error == resolveIllegalAccessError) + *exceptionptr = new_exception_message(string_java_lang_IllegalAccessException, message); + else + *exceptionptr = exceptions_new_linkageerror(message, NULL); + MFREE(message, char, msglen); + return resolveFailed; /* exception */ + } + + /* everything ok */ + + return resolveSucceeded; +} +#endif /* defined(ENABLE_VERIFIER) */ + +/* resolve_lazy_subtype_checks ************************************************* + + Resolve the types to check lazily and perform subtype checks + + IN: + refmethod........the method triggering the resolution + subtinfo.........the typeinfo containing the subtypes + supertype........the supertype to test againgst + 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. + + RETURN VALUE: + resolveSucceeded.....the check succeeded + resolveDeferred......the check could not be performed due to + unresolved types + resolveFailed........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. + +*******************************************************************************/ + +#if defined(ENABLE_VERIFIER) +static resolve_result_t resolve_lazy_subtype_checks(methodinfo *refmethod, + typeinfo *subtinfo, + classref_or_classinfo supertype, + resolve_err_t error) +{ + int count; + int i; + resolve_result_t result; + + assert(refmethod); + assert(subtinfo); + assert(supertype.any); + assert(error == resolveLinkageError || error == resolveIllegalAccessError); + + /* returnAddresses are illegal here */ + + if (TYPEINFO_IS_PRIMITIVE(*subtinfo)) { + *exceptionptr = new_verifyerror(refmethod, + "Invalid use of returnAddress"); + return resolveFailed; + } + + /* uninitialized objects are illegal here */ + + if (TYPEINFO_IS_NEWOBJECT(*subtinfo)) { + *exceptionptr = new_verifyerror(refmethod, + "Invalid use of uninitialized object"); + return resolveFailed; + } + + /* the nulltype is always assignable */ + + if (TYPEINFO_IS_NULLTYPE(*subtinfo)) + return resolveSucceeded; + + /* every type is assignable to (BOOTSTRAP)java.lang.Object */ + + if (supertype.cls == class_java_lang_Object + || (CLASSREF_OR_CLASSINFO_NAME(supertype) == utf_java_lang_Object + && refmethod->class->classloader == NULL)) + { + return resolveSucceeded; + } + + if (subtinfo->merged) { + + /* for a merged type we have to do a series of checks */ + + count = subtinfo->merged->count; + for (i=0; imerged->list[i]; + if (subtinfo->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(subtinfo->dimension,c.ref); + } + else { + c.cls = class_multiarray_of(subtinfo->dimension,c.cls,false); + } + } + + /* do the subtype check against the type c */ + + result = resolve_subtype_check(refmethod,c,supertype,resolveLazy,error); + if (result != resolveSucceeded) + return result; + } + } + else { + + /* a single type, this is the common case, hopefully */ + + if (CLASSREF_OR_CLASSINFO_NAME(subtinfo->typeclass) + == CLASSREF_OR_CLASSINFO_NAME(supertype)) + { + /* the class names are the same */ + /* equality is guaranteed by the loading constraints */ + return resolveSucceeded; + } + else { + + /* some other type name, try to perform the check lazily */ + + return resolve_subtype_check(refmethod, + subtinfo->typeclass,supertype, + resolveLazy, + error); + } + } + + /* everything ok */ + return resolveSucceeded; +} +#endif /* defined(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 + typeref..........the type to test against the set mode.............mode of resolution: resolveLazy...only resolve if it does not require loading classes @@ -444,17 +692,12 @@ bool resolve_class_from_typedesc(typedesc *d, bool checkaccess, bool link, class 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. + resolveSucceeded.....the check succeeded + resolveDeferred......the check could not be performed due to + unresolved types. (This can only happen if + mode == resolveLazy.) + resolveFailed........the check failed, an exception has been thrown. NOTE: The references in the set are resolved first, so any @@ -463,145 +706,49 @@ bool resolve_class_from_typedesc(typedesc *d, bool checkaccess, bool link, class *******************************************************************************/ -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) +#if defined(ENABLE_VERIFIER) +static resolve_result_t resolve_and_check_subtype_set(methodinfo *refmethod, + unresolved_subtype_set *ref, + classref_or_classinfo typeref, + resolve_mode_t mode, + resolve_err_t error) { classref_or_classinfo *setp; - classinfo *result; - classinfo *type; - typeinfo resultti; - typeinfo typeti; - char *message; - int msglen; - typecheck_result r; + typecheck_result checkresult; - assert(referer); + assert(refmethod); 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"); - unresolved_subtype_set_debug_dump(ref,stderr); - if (IS_CLASSREF(typeref)) { - fprintf(stderr," ref: ");utf_fprint(stderr,typeref.ref->name); - } - else { - fprintf(stderr," cls: ");utf_fprint(stderr,typeref.cls->name); - } - fprintf(stderr,"\n"); -#endif - setp = ref->subtyperefs; /* an empty set of tests always succeeds */ if (!setp || !setp->any) { - if (checked) - *checked = true; - return true; + return resolveSucceeded; } - if (checked) - *checked = false; - /* first resolve the type if necessary */ - if (!resolve_classref_or_classinfo(refmethod,typeref,mode,false,true,&type)) - return false; /* exception */ - if (!type) - return true; /* be lazy */ - - assert(type); - assert(type->state & CLASS_LOADED); - assert(type->state & CLASS_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,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 */ + if (!resolve_classref_or_classinfo(refmethod,typeref,mode,false,true,&(typeref.cls))) + return resolveFailed; /* exception */ + if (!typeref.cls) + return resolveDeferred; /* be lazy */ - assert(result); - assert(result->state & CLASS_LOADED); - assert(result->state & CLASS_LINKED); + assert(typeref.cls->state & CLASS_LINKED); + /* iterate over the set members */ - /* 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"); - fprintf(stderr," ");utf_fprint(stderr,result->name);fputc('\n',stderr); - fprintf(stderr," must be a %s of\n",(reversed) ? "superclass" : "subclass"); - fprintf(stderr," ");utf_fprint(stderr,type->name);fputc('\n',stderr); -#endif - - /* now check the subtype relationship */ - typeinfo_init_classinfo(&resultti,result); - if (reversed) { - /* we must test against `true` because `MAYBE` is also != 0 */ - 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 - goto throw_error; - } - } - else { - /* we must test against `true` because `MAYBE` is also != 0 */ - 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 - goto throw_error; - } - } + for (; setp->any; ++setp) { + checkresult = resolve_subtype_check(refmethod,*setp,typeref,mode,error); + if (checkresult != resolveSucceeded) + return checkresult; } - - /* check succeeds */ - if (checked) - *checked = true; - 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,message); - else - *exceptionptr = exceptions_new_linkageerror(message,NULL); - MFREE(message,char,msglen); - return false; /* exception */ + /* check succeeds */ + return resolveSucceeded; } - -#endif /* ENABLE_VERIFIER */ +#endif /* defined(ENABLE_VERIFIER) */ /******************************************************************************/ /* CLASS RESOLUTION */ @@ -639,7 +786,7 @@ bool resolve_class(unresolved_class *ref, classinfo **result) { classinfo *cls; - bool checked; + resolve_result_t checkresult; assert(ref); assert(result); @@ -665,17 +812,14 @@ bool resolve_class(unresolved_class *ref, assert((cls->state & CLASS_LOADED) && (cls->state & CLASS_LINKED)); /* now we check the subtype constraints */ - if (!resolve_and_check_subtype_set(ref->classref->referer,ref->referermethod, + + checkresult = resolve_and_check_subtype_set(ref->referermethod, &(ref->subtypeconstraints), CLASSREF_OR_CLASSINFO(cls), - false, mode, - resolveLinkageError,&checked)) - { - return false; /* exception */ - } - if (!checked) - return true; /* be lazy */ + resolveLinkageError); + if (checkresult != resolveSucceeded) + return (bool) checkresult; /* succeed */ *result = cls; @@ -769,259 +913,1127 @@ classinfo * resolve_class_eager(unresolved_class *ref) /* FIELD RESOLUTION */ /******************************************************************************/ -/* resolve_field *************************************************************** +/* resolve_field_verifier_checks *********************************************** - Resolve an unresolved field reference + Do the verifier checks necessary after field has been resolved. 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. + refmethod........the method containing the reference + fieldref.........the field reference + container........the class where the field was found + fi...............the fieldinfo of the resolved field + opc..............opcode of the {GET,PUT}{STATIC,FIELD} instruction RETURN VALUE: - true.............everything ok - (*result may still be NULL for resolveLazy) - false............an exception has been thrown + resolveSucceeded....everything ok + resolveDeferred.....tests could not be done, have been deferred + resolveFailed.......exception has been thrown *******************************************************************************/ -bool resolve_field(unresolved_field *ref, - resolve_mode_t mode, - fieldinfo **result) +#if defined(ENABLE_VERIFIER) +resolve_result_t resolve_field_verifier_checks(methodinfo *refmethod, + constant_FMIref *fieldref, + classinfo *container, + fieldinfo *fi, + s4 opc, + stackptr curstack) { - classinfo *referer; - classinfo *container; classinfo *declarer; + classinfo *referer; + resolve_result_t result; + bool isstatic = false; + bool isput = false; + stackelement *instanceslot = NULL; + stackelement *valueslot = NULL; constant_classref *fieldtyperef; - fieldinfo *fi; - bool checked; - - assert(ref); - assert(result); - assert(mode == resolveLazy || mode == resolveEager); - - *result = NULL; -#ifdef RESOLVE_VERBOSE - unresolved_field_debug_dump(ref,stderr); -#endif + assert(refmethod); + assert(fieldref); + assert(container); + assert(fi); - /* the class containing the reference */ + /* get the classinfos and the field type */ - referer = ref->fieldref->p.classref->referer; + referer = refmethod->class; assert(referer); - /* first we must resolve the class containg the field */ - if (!resolve_class_from_name(referer,ref->referermethod, - ref->fieldref->p.classref->name,mode,true,true,&container)) - { - /* the class reference could not be resolved */ - return false; /* exception */ - } - if (!container) - return true; /* be lazy */ + declarer = fi->class; + assert(declarer); + assert(referer->state & CLASS_LINKED); - assert(container); - assert(container->state & CLASS_LOADED); - assert(container->state & CLASS_LINKED); + fieldtyperef = fieldref->parseddesc.fd->classref; - /* now we must find the declaration of the field in `container` - * or one of its superclasses */ + /* get opcode dependent values */ -#ifdef RESOLVE_VERBOSE - fprintf(stderr," resolving field in class...\n"); -#endif + switch (opc) { + case ICMD_PUTFIELD: + isput = true; + if (curstack) { + valueslot = curstack; + instanceslot = curstack->prev; + } + break; - fi = class_resolvefield(container, - ref->fieldref->name,ref->fieldref->descriptor, - referer,true); - 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.) */ + case ICMD_PUTFIELDCONST: + isput = true; + instanceslot = curstack; + break; - *exceptionptr = NULL; - return true; /* be lazy */ - } - - return false; /* exception */ - } + case ICMD_PUTSTATIC: + isput = true; + isstatic = true; + valueslot = curstack; + break; -#ifdef ENABLE_VERIFIER + case ICMD_PUTSTATICCONST: + isput = true; + isstatic = true; + break; - /* { the field reference has been resolved } */ - declarer = fi->class; + case ICMD_GETFIELD: + instanceslot = curstack; + break; + + case ICMD_GETSTATIC: + isstatic = true; + break; + } + + /* check static */ + +#if true != 1 +#error This code assumes that `true` is `1`. Otherwise, use the ternary operator below. +#endif + + 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"); + 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); + return resolveFailed; /* exception */ + } + + /* for non-static methods we have to check the constraints on the */ + /* instance type */ + + if (instanceslot) { + typeinfo *insttip; + typeinfo tinfo; + + /* The instanceslot must contain a reference to a non-array type */ + + assert(instanceslot->type == TYPE_ADR); /* checked earlier */ + + if (!TYPEINFO_IS_REFERENCE(instanceslot->typeinfo)) { + *exceptionptr = new_verifyerror(refmethod, "illegal instruction: field access on non-reference"); + return resolveFailed; + } + if (TYPEINFO_IS_ARRAY(instanceslot->typeinfo)) { + *exceptionptr = new_verifyerror(refmethod, "illegal instruction: field access on array"); + return resolveFailed; + } + + if (isput && TYPEINFO_IS_NEWOBJECT(instanceslot->typeinfo)) + { + /* 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); + + if (ins != NULL) { + *exceptionptr = new_verifyerror(refmethod,"accessing field of uninitialized object"); + return resolveFailed; + } + + /* XXX check that class of field == refmethod->class */ + initclass = referer; /* XXX classrefs */ + assert(initclass->state & CLASS_LINKED); + + typeinfo_init_classinfo(&tinfo,initclass); + insttip = &tinfo; + } + else { + insttip = &(instanceslot->typeinfo); + } + + result = resolve_lazy_subtype_checks(refmethod, + insttip, + CLASSREF_OR_CLASSINFO(container), + resolveLinkageError); + if (result != resolveSucceeded) + return result; + + /* check protected access */ + + if (((fi->flags & ACC_PROTECTED) != 0) && !SAME_PACKAGE(declarer,referer)) + { + result = resolve_lazy_subtype_checks(refmethod, + &(instanceslot->typeinfo), + CLASSREF_OR_CLASSINFO(referer), + resolveIllegalAccessError); + if (result != resolveSucceeded) + return result; + } + + } + + /* for PUT* instructions we have to check the constraints on the value type */ + + if (valueslot && valueslot->type == TYPE_ADR) { + assert(fieldtyperef); + + /* check subtype constraints */ + result = resolve_lazy_subtype_checks(refmethod, + &(valueslot->typeinfo), + CLASSREF_OR_CLASSINFO(fieldtyperef), + resolveLinkageError); + + if (result != resolveSucceeded) + return result; + } + + /* impose loading constraint on field type */ + + if (fi->type == TYPE_ADR) { + assert(fieldtyperef); + if (!classcache_add_constraint(declarer->classloader, + referer->classloader, + fieldtyperef->name)) + return resolveFailed; + } + + /* XXX impose loading constraing on instance? */ + + /* everything ok */ + return resolveSucceeded; +} +#endif /* defined(ENABLE_VERIFIER) */ + +/* resolve_field_lazy ********************************************************** + + Resolve an unresolved field reference lazily + + IN: + iptr.............instruction containing the field reference + curstack.........instack of the instruction + refmethod........the referer method + + RETURN VALUE: + resolveSucceeded.....the reference has been resolved + resolveDeferred......the resolving could not be performed lazily + resolveFailed........resolving failed, an exception has been thrown. + +*******************************************************************************/ + +resolve_result_t new_resolve_field_lazy(new_instruction *iptr, + stackptr curstack, + methodinfo *refmethod) +{ + classinfo *referer; + classinfo *container; + fieldinfo *fi; + constant_FMIref *fieldref; + resolve_result_t result; + + assert(iptr); + assert(refmethod); + + /* the class containing the reference */ + + referer = refmethod->class; + assert(referer); + + /* get the field reference */ + + NEW_INSTRUCTION_GET_FIELDREF(iptr, fieldref); + + /* check if the field itself is already resolved */ + + if (IS_FMIREF_RESOLVED(fieldref)) { + fi = fieldref->p.field; + container = fi->class; + goto resolved_the_field; + } + + /* first we must resolve the class containg the field */ + + /* XXX can/may lazyResolving trigger linking? */ + + if (!resolve_class_from_name(referer, refmethod, + fieldref->p.classref->name, resolveLazy, true, true, &container)) + { + /* the class reference could not be resolved */ + return resolveFailed; /* exception */ + } + if (!container) + return resolveDeferred; /* be lazy */ + + assert(container->state & CLASS_LINKED); + + /* now we must find the declaration of the field in `container` + * or one of its superclasses */ + + fi = class_resolvefield(container, + fieldref->name, fieldref->descriptor, + referer, true); + if (!fi) { + /* 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 resolveDeferred; /* be lazy */ + } + + /* cache the result of the resolution */ + + fieldref->p.field = fi; + +resolved_the_field: + +#if defined(ENABLE_VERIFIER) + if (opt_verify) { + result = resolve_field_verifier_checks(refmethod, fieldref, container, + fi, + iptr->opc, + curstack); + + if (result != resolveSucceeded) + return result; + } +#endif /* defined(ENABLE_VERIFIER) */ + + /* everything ok */ + return resolveSucceeded; +} + +resolve_result_t resolve_field_lazy(instruction *iptr,stackptr curstack, + methodinfo *refmethod) +{ + classinfo *referer; + classinfo *container; + fieldinfo *fi; + constant_FMIref *fieldref; + resolve_result_t result; + + assert(iptr); + assert(refmethod); + + /* the class containing the reference */ + + referer = refmethod->class; + assert(referer); + + /* get the field reference */ + + if (iptr->opc == ICMD_PUTFIELDCONST || iptr->opc == ICMD_PUTSTATICCONST) + INSTRUCTION_GET_FIELDREF(iptr + 1,fieldref); + else + INSTRUCTION_GET_FIELDREF(iptr,fieldref); + + /* check if the field itself is already resolved */ + + if (IS_FMIREF_RESOLVED(fieldref)) { + fi = fieldref->p.field; + container = fi->class; + goto resolved_the_field; + } + + /* first we must resolve the class containg the field */ + + /* XXX can/may lazyResolving trigger linking? */ + + if (!resolve_class_from_name(referer,refmethod, + fieldref->p.classref->name,resolveLazy,true,true,&container)) + { + /* the class reference could not be resolved */ + return resolveFailed; /* exception */ + } + if (!container) + return resolveDeferred; /* be lazy */ + + assert(container->state & CLASS_LINKED); + + /* now we must find the declaration of the field in `container` + * or one of its superclasses */ + + fi = class_resolvefield(container, + fieldref->name,fieldref->descriptor, + referer,true); + if (!fi) { + /* 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 resolveDeferred; /* be lazy */ + } + + /* cache the result of the resolution */ + + fieldref->p.field = fi; + +resolved_the_field: + +#if defined(ENABLE_VERIFIER) + if (opt_verify) { + result = resolve_field_verifier_checks(refmethod,fieldref,container, + fi, + iptr->opc, + curstack); + + if (result != resolveSucceeded) + return result; + } +#endif /* defined(ENABLE_VERIFIER) */ + + /* everything ok */ + return resolveSucceeded; +} + +/* 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; + classinfo *declarer; + constant_classref *fieldtyperef; + fieldinfo *fi; + resolve_result_t checkresult; + + assert(ref); + assert(result); + assert(mode == resolveLazy || mode == resolveEager); + + *result = NULL; + +#ifdef RESOLVE_VERBOSE + unresolved_field_debug_dump(ref,stderr); +#endif + + /* the class containing the reference */ + + referer = ref->referermethod->class; + assert(referer); + + /* check if the field itself is already resolved */ + if (IS_FMIREF_RESOLVED(ref->fieldref)) { + fi = ref->fieldref->p.field; + container = fi->class; + goto resolved_the_field; + } + + /* first we must resolve the class containg the field */ + if (!resolve_class_from_name(referer,ref->referermethod, + ref->fieldref->p.classref->name,mode,true,true,&container)) + { + /* the class reference could not be resolved */ + return false; /* exception */ + } + if (!container) + return true; /* be lazy */ + + assert(container); + assert(container->state & CLASS_LOADED); + assert(container->state & CLASS_LINKED); + + /* now we must find the declaration of the field in `container` + * or one of its superclasses */ + +#ifdef RESOLVE_VERBOSE + fprintf(stderr," resolving field in class...\n"); +#endif + + fi = class_resolvefield(container, + ref->fieldref->name,ref->fieldref->descriptor, + referer,true); + 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 */ + } + + /* cache the result of the resolution */ + ref->fieldref->p.field = fi; + +resolved_the_field: + +#ifdef ENABLE_VERIFIER + if (opt_verify) { + checkresult = resolve_field_verifier_checks(ref->referermethod, + ref->fieldref, + container, + fi, + /* XXX pass NULL instruction * */ + (ref->flags & RESOLVE_STATIC) ? ICMD_GETSTATIC : ICMD_GETFIELD, + NULL); + + if (checkresult != resolveSucceeded) + return (bool) checkresult; + + declarer = fi->class; + assert(declarer); + assert(declarer->state & CLASS_LOADED); + assert(declarer->state & CLASS_LINKED); + + /* for non-static accesses we have to check the constraints on the */ + /* instance type */ + + if (!(ref->flags & RESOLVE_STATIC)) { + checkresult = resolve_and_check_subtype_set(ref->referermethod, + &(ref->instancetypes), + CLASSREF_OR_CLASSINFO(container), + mode, resolveLinkageError); + if (checkresult != resolveSucceeded) + return (bool) checkresult; + } + + 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) { + assert(fieldtyperef); + if (!SUBTYPESET_IS_EMPTY(ref->valueconstraints)) { + /* check subtype constraints */ + checkresult = resolve_and_check_subtype_set(ref->referermethod, + &(ref->valueconstraints), + CLASSREF_OR_CLASSINFO(fieldtyperef), + mode, resolveLinkageError); + if (checkresult != resolveSucceeded) + return (bool) checkresult; + } + } + + /* check protected access */ + if (((fi->flags & ACC_PROTECTED) != 0) && !SAME_PACKAGE(declarer,referer)) { + checkresult = resolve_and_check_subtype_set(ref->referermethod, + &(ref->instancetypes), + CLASSREF_OR_CLASSINFO(referer), + mode, + resolveIllegalAccessError); + if (checkresult != resolveSucceeded) + return (bool) checkresult; + } + + } +#endif /* ENABLE_VERIFIER */ + + /* succeed */ + *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 */ +/******************************************************************************/ + +/* resolve_method_invokespecial_lookup ***************************************** + + Do the special lookup for methods invoked by INVOKESPECIAL + + IN: + refmethod........the method containing the reference + mi...............the methodinfo of the resolved method + + RETURN VALUE: + a methodinfo *...the result of the lookup, + NULL.............an exception has been thrown + +*******************************************************************************/ + +methodinfo * resolve_method_invokespecial_lookup(methodinfo *refmethod, + methodinfo *mi) +{ + classinfo *declarer; + classinfo *referer; + + assert(refmethod); + assert(mi); + + /* get referer and declarer classes */ + + referer = refmethod->class; + assert(referer); + + declarer = mi->class; assert(declarer); - assert(declarer->state & CLASS_LOADED); - assert(declarer->state & CLASS_LINKED); + assert(referer->state & CLASS_LINKED); + + /* checks for INVOKESPECIAL: */ + /* for 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 ((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(refmethod, + "INVOKESPECIAL calling non-super class method"); + return NULL; + } + + /* 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, + mi->name, + mi->descriptor); + + if (mi == NULL) { + /* the spec calls for an AbstractMethodError in this case */ + exceptions_throw_abstractmethoderror(); + return NULL; + } + } + } + + /* everything ok */ + return mi; +} + +/* resolve_method_verifier_checks ********************************************** + + Do the verifier checks necessary after a method has been resolved. + + IN: + refmethod........the method containing the reference + methodref........the method reference + container........the class where the method was found + mi...............the methodinfo of the resolved method + invokestatic.....true if the method is invoked by INVOKESTATIC + + RETURN VALUE: + resolveSucceeded....everything ok + resolveDeferred.....tests could not be done, have been deferred + resolveFailed.......exception has been thrown + +*******************************************************************************/ + +#if defined(ENABLE_VERIFIER) +resolve_result_t resolve_method_verifier_checks(methodinfo *refmethod, + constant_FMIref *methodref, + classinfo *container, + methodinfo *mi, + bool invokestatic, + bool invokespecial, + stackptr curstack) +{ + classinfo *declarer; + classinfo *referer; + resolve_result_t result; + int instancecount; + typedesc *paramtypes; + int i; + stackelement *instanceslot = NULL; + stackelement *param; + methoddesc *md; + typeinfo tinfo; + int type; + + assert(refmethod); + assert(methodref); + assert(container); + assert(mi); #ifdef RESOLVE_VERBOSE - fprintf(stderr," checking static...\n"); + fprintf(stderr,"resolve_method_verifier_checks\n"); + fprintf(stderr," flags: %02x\n",mi->flags); #endif + /* get the classinfos and the method descriptor */ + + referer = refmethod->class; + assert(referer); + + declarer = mi->class; + assert(declarer); + assert(referer->state & CLASS_LINKED); + + md = methodref->parseddesc.md; + assert(md); + assert(md->params); + + instancecount = (invokestatic) ? 0 : 1; + /* 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, - (fi->flags & ACC_STATIC) ? "static field accessed via instance" - : "instance field accessed without instance"); - return false; /* exception */ + 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"); + return resolveFailed; } - /* for non-static accesses we have to check the constraints on the */ - /* instance type */ + /* check access rights */ - if (!(ref->flags & RESOLVE_STATIC)) { -#ifdef RESOLVE_VERBOSE - fprintf(stderr," checking instance types...\n"); -#endif + if (!access_is_accessible_member(referer,declarer,mi->flags)) { + int msglen; + char *message; - if (!resolve_and_check_subtype_set(referer,ref->referermethod, - &(ref->instancetypes), - CLASSREF_OR_CLASSINFO(container), - false, mode, resolveLinkageError, - &checked)) - { - return false; /* exception */ + /* 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); + return resolveFailed; /* exception */ + } + + if (curstack) { + /* for non-static methods we have to check the constraints on the */ + /* instance type */ + + if (!invokestatic) { + /* find the instance slot under all the parameter slots on the stack */ + instanceslot = curstack; + for (i=1; iparamcount; ++i) + instanceslot = instanceslot->prev; } - if (!checked) - return true; /* be lazy */ - } + assert((instanceslot && instancecount == 1) || invokestatic); -#ifdef RESOLVE_VERBOSE - fprintf(stderr," checking instance types...done\n"); -#endif + /* record subtype constraints for the instance type, if any */ + if (instanceslot) { + typeinfo *tip; - fieldtyperef = ref->fieldref->parseddesc.fd->classref; + assert(instanceslot->type == TYPE_ADR); - /* for PUT* instructions we have to check the constraints on the value type */ - if (((ref->flags & RESOLVE_PUTFIELD) != 0) && fi->type == TYPE_ADR) { -#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, - &(ref->valueconstraints), - CLASSREF_OR_CLASSINFO(fieldtyperef), - false, mode, resolveLinkageError, - &checked)) + if (invokespecial && + TYPEINFO_IS_NEWOBJECT(instanceslot->typeinfo)) + { /* XXX clean up */ + instruction *ins = (instruction*)TYPEINFO_NEWOBJECT_INSTRUCTION(instanceslot->typeinfo); + classref_or_classinfo initclass = (ins) ? ICMD_ACONST_CLASSREF_OR_CLASSINFO(ins-1) + : CLASSREF_OR_CLASSINFO(refmethod->class); + tip = &tinfo; + if (!typeinfo_init_class(tip,initclass)) + return false; + } + else { + tip = &(instanceslot->typeinfo); + } + + result = resolve_lazy_subtype_checks(refmethod, + tip, + CLASSREF_OR_CLASSINFO(container), + resolveLinkageError); + if (result != resolveSucceeded) + return result; + + /* check protected access */ + + if (((mi->flags & ACC_PROTECTED) != 0) && !SAME_PACKAGE(declarer,referer)) { - return false; /* exception */ + result = resolve_lazy_subtype_checks(refmethod, + tip, + CLASSREF_OR_CLASSINFO(referer), + resolveIllegalAccessError); + if (result != resolveSucceeded) + return result; } - if (!checked) - return true; /* be lazy */ + + } + + /* check subtype constraints for TYPE_ADR parameters */ + + assert(md->paramcount == methodref->parseddesc.md->paramcount); + paramtypes = md->paramtypes; + param = curstack; + + 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) { + result = resolve_lazy_subtype_checks(refmethod, + &(param->typeinfo), + CLASSREF_OR_CLASSINFO(paramtypes[i+instancecount].classref), + resolveLinkageError); + if (result != resolveSucceeded) + return result; + } + } + + } /* if (curstack) */ + + /* impose loading constraints on parameters (including instance) */ + + paramtypes = md->paramtypes; + + for (i = 0; i < md->paramcount; i++) { + if (i < instancecount || paramtypes[i].type == TYPE_ADR) { + utf *name; + + if (i < instancecount) { + /* The type of the 'this' pointer is the class containing */ + /* the method definition. Since container is the same as, */ + /* or a subclass of declarer, we also constrain declarer */ + /* by transitivity of loading constraints. */ + name = container->name; + } + else { + name = paramtypes[i].classref->name; + } + + /* The caller (referer) and the callee (container) must agree */ + /* on the types of the parameters. */ + if (!classcache_add_constraint(referer->classloader, + container->classloader, name)) + return resolveFailed; /* exception */ } } - - /* check access rights */ -#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 */ + /* impose loading constraint onto return type */ + + if (md->returntype.type == TYPE_ADR) { + /* The caller (referer) and the callee (container) must agree */ + /* on the return type. */ + if (!classcache_add_constraint(referer->classloader,container->classloader, + md->returntype.classref->name)) + return resolveFailed; /* 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)) { + /* everything ok */ + return resolveSucceeded; +} +#endif /* defined(ENABLE_VERIFIER) */ + +/* resolve_method_lazy ********************************************************* + + Resolve an unresolved method reference lazily + + IN: + iptr.............instruction containing the method reference + curstack.........instack of the instruction + refmethod........the referer method + + RETURN VALUE: + resolveSucceeded.....the reference has been resolved + resolveDeferred......the resolving could not be performed lazily + resolveFailed........resolving failed, an exception has been thrown. + +*******************************************************************************/ + +resolve_result_t new_resolve_method_lazy(new_instruction *iptr, + stackptr curstack, + methodinfo *refmethod) +{ + classinfo *referer; + classinfo *container; + methodinfo *mi; + constant_FMIref *methodref; + resolve_result_t result; + + assert(iptr); + assert(refmethod); + #ifdef RESOLVE_VERBOSE - fprintf(stderr," checking protected access...\n"); + fprintf(stderr,"resolve_method_lazy\n"); #endif - if (!resolve_and_check_subtype_set(referer,ref->referermethod, - &(ref->instancetypes), - CLASSREF_OR_CLASSINFO(referer), - false, mode, - resolveIllegalAccessError, &checked)) - { - return false; /* exception */ - } - if (!checked) - return true; /* be lazy */ + /* the class containing the reference */ + + referer = refmethod->class; + assert(referer); + + /* the method reference */ + + NEW_INSTRUCTION_GET_METHODREF(iptr, methodref); + + /* check if the method itself is already resolved */ + + if (IS_FMIREF_RESOLVED(methodref)) { + mi = methodref->p.method; + container = mi->class; + goto resolved_the_method; } - /* impose loading constraint on field type */ + /* first we must resolve the class containg the method */ + + if (!resolve_class_from_name(referer, refmethod, + methodref->p.classref->name, resolveLazy, true, true, &container)) + { + /* the class reference could not be resolved */ + return resolveFailed; /* exception */ + } + if (!container) + return resolveDeferred; /* be lazy */ + + assert(container->state & CLASS_LINKED); + + /* now we must find the declaration of the method in `container` + * or one of its superclasses */ + + if (container->flags & ACC_INTERFACE) { + mi = class_resolveinterfacemethod(container, + methodref->name, + methodref->descriptor, + referer, true); + + } else { + mi = class_resolveclassmethod(container, + methodref->name, + methodref->descriptor, + referer, true); + } + + if (!mi) { + /* 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 resolveDeferred; /* be lazy */ + } + + if (iptr->opc == ICMD_INVOKESPECIAL) { + mi = resolve_method_invokespecial_lookup(refmethod, mi); + if (!mi) + return resolveFailed; /* exception */ + } + + /* have the method params already been parsed? no, do it. */ + + if (!mi->parseddesc->params) + if (!descriptor_params_from_paramtypes(mi->parseddesc, mi->flags)) + return resolveFailed; + + /* cache the result of the resolution */ + + methodref->p.method = mi; + +resolved_the_method: + +#if defined(ENABLE_VERIFIER) + if (opt_verify) { + result = resolve_method_verifier_checks(refmethod, methodref, + container, + mi, + iptr->opc == ICMD_INVOKESTATIC, + iptr->opc == ICMD_INVOKESPECIAL, + curstack); + if (result != resolveSucceeded) + return result; + } +#endif /* defined(ENABLE_VERIFIER) */ + + /* if this call is monomorphic, turn it into an INVOKESPECIAL */ + + if ((iptr->opc == ICMD_INVOKEVIRTUAL) + && (mi->flags & (ACC_FINAL | ACC_PRIVATE))) + { + iptr->opc = ICMD_INVOKESPECIAL; + } + + /* succeed */ + return resolveSucceeded; +} + +resolve_result_t resolve_method_lazy(instruction *iptr,stackptr curstack, + methodinfo *refmethod) +{ + classinfo *referer; + classinfo *container; + methodinfo *mi; + constant_FMIref *methodref; + resolve_result_t result; + + assert(iptr); + assert(refmethod); - if (fi->type == TYPE_ADR) { #ifdef RESOLVE_VERBOSE - fprintf(stderr," adding constraint...\n"); + fprintf(stderr,"resolve_method_lazy\n"); #endif - assert(fieldtyperef); - if (!classcache_add_constraint(declarer->classloader, - referer->classloader, - fieldtyperef->name)) - return false; + + /* the class containing the reference */ + + referer = refmethod->class; + assert(referer); + + /* the method reference */ + + INSTRUCTION_GET_METHODREF(iptr,methodref); + + /* check if the method itself is already resolved */ + + if (IS_FMIREF_RESOLVED(methodref)) { + mi = methodref->p.method; + container = mi->class; + goto resolved_the_method; } -#endif /* ENABLE_VERIFIER */ - /* succeed */ -#ifdef RESOLVE_VERBOSE - fprintf(stderr," success.\n"); -#endif - *result = fi; + /* first we must resolve the class containg the method */ + + if (!resolve_class_from_name(referer,refmethod, + methodref->p.classref->name,resolveLazy,true,true,&container)) + { + /* the class reference could not be resolved */ + return resolveFailed; /* exception */ + } + if (!container) + return resolveDeferred; /* be lazy */ + + assert(container->state & CLASS_LINKED); + + /* now we must find the declaration of the method in `container` + * or one of its superclasses */ + + if (container->flags & ACC_INTERFACE) { + mi = class_resolveinterfacemethod(container, + methodref->name, + methodref->descriptor, + referer, true); + + } else { + mi = class_resolveclassmethod(container, + methodref->name, + methodref->descriptor, + referer, true); + } + + if (!mi) { + /* 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 resolveDeferred; /* be lazy */ + } + + if (iptr->opc == ICMD_INVOKESPECIAL) { + mi = resolve_method_invokespecial_lookup(refmethod,mi); + if (!mi) + return resolveFailed; /* exception */ + } + + /* have the method params already been parsed? no, do it. */ + + if (!mi->parseddesc->params) + if (!descriptor_params_from_paramtypes(mi->parseddesc, mi->flags)) + return resolveFailed; + + /* cache the result of the resolution */ - return true; -} + methodref->p.method = mi; -/* 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 - -*******************************************************************************/ +resolved_the_method: -fieldinfo * resolve_field_eager(unresolved_field *ref) -{ - fieldinfo *fi; +#if defined(ENABLE_VERIFIER) + if (opt_verify) { + result = resolve_method_verifier_checks(refmethod,methodref,container, + mi, + iptr->opc == ICMD_INVOKESTATIC, + iptr->opc == ICMD_INVOKESPECIAL, + curstack); + if (result != resolveSucceeded) + return result; + } +#endif /* defined(ENABLE_VERIFIER) */ - if (!resolve_field(ref,resolveEager,&fi)) - return NULL; + /* if this call is monomorphic, turn it into an INVOKESPECIAL */ - return fi; -} + if ((iptr->opc == ICMD_INVOKEVIRTUAL) + && (mi->flags & (ACC_FINAL | ACC_PRIVATE))) + { + iptr->opc = ICMD_INVOKESPECIAL; + } -/******************************************************************************/ -/* METHOD RESOLUTION */ -/******************************************************************************/ + /* succeed */ + return resolveSucceeded; +} /* resolve_method ************************************************************** @@ -1056,8 +2068,8 @@ bool resolve_method(unresolved_method *ref, resolve_mode_t mode, methodinfo **re typedesc *paramtypes; int instancecount; int i; - bool checked; - + resolve_result_t checkresult; + assert(ref); assert(result); assert(mode == resolveLazy || mode == resolveEager); @@ -1069,10 +2081,20 @@ bool resolve_method(unresolved_method *ref, resolve_mode_t mode, methodinfo **re *result = NULL; /* the class containing the reference */ - referer = ref->methodref->p.classref->referer; + + referer = ref->referermethod->class; assert(referer); - /* first we must resolve the class containg the method */ + /* check if the method itself is already resolved */ + + if (IS_FMIREF_RESOLVED(ref->methodref)) { + mi = ref->methodref->p.method; + container = mi->class; + goto resolved_the_method; + } + + /* first we must resolve the class containing the method */ + if (!resolve_class_from_name(referer,ref->referermethod, ref->methodref->p.classref->name,mode,true,true,&container)) { @@ -1110,60 +2132,16 @@ bool resolve_method(unresolved_method *ref, resolve_mode_t mode, methodinfo **re *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; - assert(declarer); - assert(referer->state & CLASS_LINKED); - - /* checks for INVOKESPECIAL: */ - /* for 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, - (mi->flags & ACC_STATIC) ? "static method called via instance" - : "instance method called without instance"); - return false; + if (ref->flags & RESOLVE_SPECIAL) { + mi = resolve_method_invokespecial_lookup(ref->referermethod,mi); + if (!mi) + return false; /* exception */ } /* have the method params already been parsed? no, do it. */ @@ -1171,127 +2149,80 @@ bool resolve_method(unresolved_method *ref, resolve_mode_t mode, methodinfo **re 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), - false, - mode, - resolveLinkageError,&checked)) - { - return false; /* exception */ + /* cache the resolution */ + + ref->methodref->p.method = mi; + +resolved_the_method: + +#ifdef ENABLE_VERIFIER + if (opt_verify) { + + checkresult = resolve_method_verifier_checks(ref->referermethod, + ref->methodref, + container, + mi, + (ref->flags & RESOLVE_STATIC), + (ref->flags & RESOLVE_SPECIAL), + NULL); + + if (checkresult != resolveSucceeded) + return (bool) checkresult; + + declarer = mi->class; + assert(declarer); + assert(referer->state & CLASS_LINKED); + + /* for non-static methods we have to check the constraints on the */ + /* instance type */ + + if (!(ref->flags & RESOLVE_STATIC)) { + checkresult = resolve_and_check_subtype_set(ref->referermethod, + &(ref->instancetypes), + CLASSREF_OR_CLASSINFO(container), + mode, + resolveLinkageError); + if (checkresult != resolveSucceeded) + return (bool) checkresult; + instancecount = 1; + } + else { + instancecount = 0; } - if (!checked) - return true; /* be lazy */ - instancecount = 1; - } - else { - instancecount = 0; - } - /* check subtype constraints for TYPE_ADR parameters */ + /* check subtype constraints for TYPE_ADR parameters */ - assert(mi->parseddesc->paramcount == ref->methodref->parseddesc.md->paramcount); - paramtypes = mi->parseddesc->paramtypes; - - 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, + assert(mi->parseddesc->paramcount == ref->methodref->parseddesc.md->paramcount); + paramtypes = mi->parseddesc->paramtypes; + + for (i = 0; i < mi->parseddesc->paramcount-instancecount; i++) { + if (paramtypes[i+instancecount].type == TYPE_ADR) { + if (ref->paramconstraints) { + checkresult = resolve_and_check_subtype_set(ref->referermethod, ref->paramconstraints + i, CLASSREF_OR_CLASSINFO(paramtypes[i+instancecount].classref), - false, mode, - resolveLinkageError,&checked)) - { - return false; /* exception */ + resolveLinkageError); + if (checkresult != resolveSucceeded) + return (bool) checkresult; } - if (!checked) - return true; /* be lazy */ } } - } - - /* check access rights */ - - 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 */ + /* check protected access */ - 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), - false, - mode, - resolveIllegalAccessError,&checked)) + if (((mi->flags & ACC_PROTECTED) != 0) && !SAME_PACKAGE(declarer,referer)) { - return false; /* exception */ - } - if (!checked) - return true; /* be lazy */ - } - - /* impose loading constraints on parameters (including instance) */ - - 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) { - /* The type of the 'this' pointer is the class containing */ - /* the method definition. Since container is the same as, */ - /* or a subclass of declarer, we also constrain declarer */ - /* by transitivity of loading constraints. */ - name = container->name; - } - else { - name = paramtypes[i].classref->name; - } - - /* The caller (referer) and the callee (container) must agree */ - /* on the types of the parameters. */ - if (!classcache_add_constraint(referer->classloader, - container->classloader, name)) - return false; /* exception */ + checkresult = resolve_and_check_subtype_set(ref->referermethod, + &(ref->instancetypes), + CLASSREF_OR_CLASSINFO(referer), + mode, + resolveIllegalAccessError); + if (checkresult != resolveSucceeded) + return (bool) checkresult; } } - - /* impose loading constraint onto return type */ - - if (ref->methodref->parseddesc.md->returntype.type == TYPE_ADR) { - /* The caller (referer) and the callee (container) must agree */ - /* on the return type. */ - if (!classcache_add_constraint(referer->classloader,container->classloader, - ref->methodref->parseddesc.md->returntype.classref->name)) - return false; /* exception */ - } - #endif /* ENABLE_VERIFIER */ /* succeed */ @@ -1335,7 +2266,7 @@ static bool unresolved_subtype_set_from_typeinfo(classinfo *referer, { int count; int i; - + assert(stset); assert(tinfo); @@ -1344,7 +2275,7 @@ static bool unresolved_subtype_set_from_typeinfo(classinfo *referer, #ifdef TYPEINFO_DEBUG typeinfo_print(stderr,tinfo,4); #endif - fprintf(stderr," declared type:");utf_fprint(stderr,declaredtype->name); + fprintf(stderr," declared type:");utf_fprint_printable_ascii(stderr,declaredtype->name); fprintf(stderr,"\n"); #endif @@ -1360,7 +2291,7 @@ static bool unresolved_subtype_set_from_typeinfo(classinfo *referer, return false; } - /* the nulltype is always assignable (XXX for reversed?) */ + /* the nulltype is always assignable */ if (TYPEINFO_IS_NULLTYPE(*tinfo)) goto empty_set; @@ -1393,7 +2324,7 @@ static bool unresolved_subtype_set_from_typeinfo(classinfo *referer, } else { if ((IS_CLASSREF(tinfo->typeclass) - ? tinfo->typeclass.ref->name + ? tinfo->typeclass.ref->name : tinfo->typeclass.cls->name) == declaredtype->name) { /* the class names are the same */ @@ -1437,15 +2368,15 @@ unresolved_class * create_unresolved_class(methodinfo *refmethod, 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); + fprintf(stderr," referer: ");utf_fprint_printable_ascii(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," rmethod: ");utf_fprint_printable_ascii(stderr,refmethod->name);fputc('\n',stderr); + fprintf(stderr," rmdesc : ");utf_fprint_printable_ascii(stderr,refmethod->descriptor);fputc('\n',stderr); } - fprintf(stderr," name : ");utf_fprint(stderr,classref->name);fputc('\n',stderr); + fprintf(stderr," name : ");utf_fprint_printable_ascii(stderr,classref->name);fputc('\n',stderr); #endif ref = NEW(unresolved_class); @@ -1480,6 +2411,73 @@ unresolved_class * create_unresolved_class(methodinfo *refmethod, *******************************************************************************/ +unresolved_field * new_create_unresolved_field(classinfo *referer, + methodinfo *refmethod, + new_instruction *iptr) +{ + unresolved_field *ref; + constant_FMIref *fieldref = NULL; + +#ifdef RESOLVE_VERBOSE + fprintf(stderr,"create_unresolved_field\n"); + fprintf(stderr," referer: ");utf_fprint_printable_ascii(stderr,referer->name);fputc('\n',stderr); + fprintf(stderr," rmethod: ");utf_fprint_printable_ascii(stderr,refmethod->name);fputc('\n',stderr); + fprintf(stderr," rmdesc : ");utf_fprint_printable_ascii(stderr,refmethod->descriptor);fputc('\n',stderr); +#endif + + ref = NEW(unresolved_field); + ref->flags = 0; + ref->referermethod = refmethod; + UNRESOLVED_SUBTYPE_SET_EMTPY(ref->valueconstraints); + + switch (iptr->opc) { + case ICMD_PUTFIELD: + ref->flags |= RESOLVE_PUTFIELD; + break; + + case ICMD_PUTFIELDCONST: + ref->flags |= RESOLVE_PUTFIELD; + break; + + case ICMD_PUTSTATIC: + ref->flags |= RESOLVE_PUTFIELD | RESOLVE_STATIC; + break; + + case ICMD_PUTSTATICCONST: + ref->flags |= RESOLVE_PUTFIELD | RESOLVE_STATIC; + break; + + case ICMD_GETFIELD: + break; + + case ICMD_GETSTATIC: + ref->flags |= RESOLVE_STATIC; + break; + +#if !defined(NDEBUG) + default: + assert(false); +#endif + } + + fieldref = iptr->sx.s23.s3.fmiref; + + assert(fieldref); + +#ifdef RESOLVE_VERBOSE + fprintf(stderr," class : ");utf_fprint_printable_ascii(stderr,fieldref->classref->name);fputc('\n',stderr); + fprintf(stderr," name : ");utf_fprint_printable_ascii(stderr,fieldref->name);fputc('\n',stderr); + fprintf(stderr," desc : ");utf_fprint_printable_ascii(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->opc,icmd_names[iptr->opc]);*/ +#endif + + ref->fieldref = fieldref; + + return ref; +} + unresolved_field * create_unresolved_field(classinfo *referer, methodinfo *refmethod, instruction *iptr) { @@ -1488,9 +2486,9 @@ unresolved_field * create_unresolved_field(classinfo *referer, methodinfo *refme #ifdef RESOLVE_VERBOSE fprintf(stderr,"create_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," referer: ");utf_fprint_printable_ascii(stderr,referer->name);fputc('\n',stderr); + fprintf(stderr," rmethod: ");utf_fprint_printable_ascii(stderr,refmethod->name);fputc('\n',stderr); + fprintf(stderr," rmdesc : ");utf_fprint_printable_ascii(stderr,refmethod->descriptor);fputc('\n',stderr); #endif ref = NEW(unresolved_field); @@ -1522,19 +2520,19 @@ unresolved_field * create_unresolved_field(classinfo *referer, methodinfo *refme case ICMD_GETFIELD: fieldref = (constant_FMIref *) iptr[0].val.a; break; - + case ICMD_GETSTATIC: ref->flags |= RESOLVE_STATIC; fieldref = (constant_FMIref *) iptr[0].val.a; break; } - + assert(fieldref); #ifdef RESOLVE_VERBOSE - 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," class : ");utf_fprint_printable_ascii(stderr,fieldref->classref->name);fputc('\n',stderr); + fprintf(stderr," name : ");utf_fprint_printable_ascii(stderr,fieldref->name);fputc('\n',stderr); + fprintf(stderr," desc : ");utf_fprint_printable_ascii(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]);*/ @@ -1582,12 +2580,12 @@ bool constrain_unresolved_field(unresolved_field *ref, #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," referer: ");utf_fprint_printable_ascii(stderr,referer->name);fputc('\n',stderr); + fprintf(stderr," rmethod: ");utf_fprint_printable_ascii(stderr,refmethod->name);fputc('\n',stderr); + fprintf(stderr," rmdesc : ");utf_fprint_printable_ascii(stderr,refmethod->descriptor);fputc('\n',stderr); + fprintf(stderr," class : ");utf_fprint_printable_ascii(stderr,fieldref->classref->name);fputc('\n',stderr); + fprintf(stderr," name : ");utf_fprint_printable_ascii(stderr,fieldref->name);fputc('\n',stderr); + fprintf(stderr," desc : ");utf_fprint_printable_ascii(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]);*/ @@ -1611,7 +2609,7 @@ bool constrain_unresolved_field(unresolved_field *ref, instanceslot = stack; break; } - + assert(instanceslot || ((ref->flags & RESOLVE_STATIC) != 0)); fd = fieldref->parseddesc.fd; assert(fd); @@ -1629,14 +2627,14 @@ bool constrain_unresolved_field(unresolved_field *ref, *exceptionptr = new_verifyerror(refmethod, "illegal instruction: field access on array"); return false; } - - if (((ref->flags & RESOLVE_PUTFIELD) != 0) && + + if (((ref->flags & RESOLVE_PUTFIELD) != 0) && TYPEINFO_IS_NEWOBJECT(instanceslot->typeinfo)) { /* 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); @@ -1662,7 +2660,7 @@ bool constrain_unresolved_field(unresolved_field *ref, else { UNRESOLVED_SUBTYPE_SET_EMTPY(ref->instancetypes); } - + /* record subtype constraints for the value type, if any */ type = fd->type; if (type == TYPE_ADR && ((ref->flags & RESOLVE_PUTFIELD) != 0)) { @@ -1705,6 +2703,47 @@ bool constrain_unresolved_field(unresolved_field *ref, *******************************************************************************/ +unresolved_method * new_create_unresolved_method(classinfo *referer, + methodinfo *refmethod, + new_instruction *iptr) +{ + unresolved_method *ref; + constant_FMIref *methodref; + bool staticmethod; + + methodref = iptr->sx.s23.s3.fmiref; + assert(methodref); + staticmethod = (iptr->opc == ICMD_INVOKESTATIC); + +#ifdef RESOLVE_VERBOSE + fprintf(stderr,"create_unresolved_method\n"); + fprintf(stderr," referer: ");utf_fprint_printable_ascii(stderr,referer->name);fputc('\n',stderr); + fprintf(stderr," rmethod: ");utf_fprint_printable_ascii(stderr,refmethod->name);fputc('\n',stderr); + fprintf(stderr," rmdesc : ");utf_fprint_printable_ascii(stderr,refmethod->descriptor);fputc('\n',stderr); + fprintf(stderr," class : ");utf_fprint_printable_ascii(stderr,methodref->classref->name);fputc('\n',stderr); + fprintf(stderr," name : ");utf_fprint_printable_ascii(stderr,methodref->name);fputc('\n',stderr); + fprintf(stderr," desc : ");utf_fprint_printable_ascii(stderr,methodref->descriptor);fputc('\n',stderr); + /*fprintf(stderr," opcode : %d %s\n",iptr->opc,icmd_names[iptr->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 = ((staticmethod) ? RESOLVE_STATIC : 0) + | ((iptr->opc == ICMD_INVOKESPECIAL) ? RESOLVE_SPECIAL : 0); + ref->referermethod = refmethod; + ref->methodref = methodref; + ref->paramconstraints = NULL; + UNRESOLVED_SUBTYPE_SET_EMTPY(ref->instancetypes); + + return ref; +} + unresolved_method * create_unresolved_method(classinfo *referer, methodinfo *refmethod, instruction *iptr) { @@ -1718,12 +2757,12 @@ unresolved_method * create_unresolved_method(classinfo *referer, methodinfo *ref #ifdef RESOLVE_VERBOSE fprintf(stderr,"create_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," referer: ");utf_fprint_printable_ascii(stderr,referer->name);fputc('\n',stderr); + fprintf(stderr," rmethod: ");utf_fprint_printable_ascii(stderr,refmethod->name);fputc('\n',stderr); + fprintf(stderr," rmdesc : ");utf_fprint_printable_ascii(stderr,refmethod->descriptor);fputc('\n',stderr); + fprintf(stderr," class : ");utf_fprint_printable_ascii(stderr,methodref->classref->name);fputc('\n',stderr); + fprintf(stderr," name : ");utf_fprint_printable_ascii(stderr,methodref->name);fputc('\n',stderr); + fprintf(stderr," desc : ");utf_fprint_printable_ascii(stderr,methodref->descriptor);fputc('\n',stderr); /*fprintf(stderr," opcode : %d %s\n",iptr[0].opc,icmd_names[iptr[0].opc]);*/ #endif @@ -1769,6 +2808,7 @@ bool constrain_unresolved_method(unresolved_method *ref, stackelement *stack) { constant_FMIref *methodref; + constant_classref *instanceref; stackelement *instanceslot = NULL; stackelement *param; methoddesc *md; @@ -1784,14 +2824,19 @@ bool constrain_unresolved_method(unresolved_method *ref, assert(md); assert(md->params != NULL); + /* XXX clean this up */ + instanceref = IS_FMIREF_RESOLVED(methodref) + ? class_get_self_classref(methodref->p.method->class) + : methodref->p.classref; + #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," referer: ");utf_fprint_printable_ascii(stderr,referer->name);fputc('\n',stderr); + fprintf(stderr," rmethod: ");utf_fprint_printable_ascii(stderr,refmethod->name);fputc('\n',stderr); + fprintf(stderr," rmdesc : ");utf_fprint_printable_ascii(stderr,refmethod->descriptor);fputc('\n',stderr); + fprintf(stderr," class : ");utf_fprint_printable_ascii(stderr,methodref->classref->name);fputc('\n',stderr); + fprintf(stderr," name : ");utf_fprint_printable_ascii(stderr,methodref->name);fputc('\n',stderr); + fprintf(stderr," desc : ");utf_fprint_printable_ascii(stderr,methodref->descriptor);fputc('\n',stderr); /*fprintf(stderr," opcode : %d %s\n",iptr[0].opc,icmd_names[iptr[0].opc]);*/ #endif @@ -1805,20 +2850,20 @@ bool constrain_unresolved_method(unresolved_method *ref, else { instancecount = 0; } - + assert((instanceslot && instancecount==1) || ((ref->flags & RESOLVE_STATIC) != 0)); /* record subtype constraints for the instance type, if any */ if (instanceslot) { typeinfo *tip; - + assert(instanceslot->type == TYPE_ADR); - - if (iptr[0].opc == ICMD_INVOKESPECIAL && + + if (iptr[0].opc == ICMD_INVOKESPECIAL && TYPEINFO_IS_NEWOBJECT(instanceslot->typeinfo)) { /* XXX clean up */ instruction *ins = (instruction*)TYPEINFO_NEWOBJECT_INSTRUCTION(instanceslot->typeinfo); - classref_or_classinfo initclass = (ins) ? CLASSREF_OR_CLASSINFO(ins[-1].target) + classref_or_classinfo initclass = (ins) ? ICMD_ACONST_CLASSREF_OR_CLASSINFO(ins-1) : CLASSREF_OR_CLASSINFO(refmethod->class); tip = &tinfo; if (!typeinfo_init_class(tip,initclass)) @@ -1828,10 +2873,10 @@ bool constrain_unresolved_method(unresolved_method *ref, tip = &(instanceslot->typeinfo); } if (!unresolved_subtype_set_from_typeinfo(referer,refmethod, - &(ref->instancetypes),tip,methodref->p.classref)) + &(ref->instancetypes),tip,instanceref)) return false; } - + /* record subtype constraints for the parameter types, if any */ param = stack; for (i=md->paramcount-1-instancecount; i>=0; --i, param=param->prev) { @@ -1946,11 +2991,12 @@ void unresolved_method_free(unresolved_method *ref) FREE(ref,unresolved_method); } -#ifndef NDEBUG /******************************************************************************/ /* DEBUG DUMPS */ /******************************************************************************/ +#if !defined(NDEBUG) + /* unresolved_subtype_set_debug_dump ******************************************* Print debug info for unresolved_subtype_set to stream @@ -1964,7 +3010,7 @@ void unresolved_method_free(unresolved_method *ref) void unresolved_subtype_set_debug_dump(unresolved_subtype_set *stset,FILE *file) { classref_or_classinfo *p; - + if (SUBTYPESET_IS_EMPTY(*stset)) { fprintf(file," (empty)\n"); } @@ -1973,11 +3019,11 @@ void unresolved_subtype_set_debug_dump(unresolved_subtype_set *stset,FILE *file) for (;p->any; ++p) { if (IS_CLASSREF(*p)) { fprintf(file," ref: "); - utf_fprint(file,p->ref->name); + utf_fprint_printable_ascii(file,p->ref->name); } else { fprintf(file," cls: "); - utf_fprint(file,p->cls->name); + utf_fprint_printable_ascii(file,p->cls->name); } fputc('\n',file); } @@ -1999,13 +3045,13 @@ 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); + utf_fprint_printable_ascii(file,ref->classref->referer->name); fputc('\n',file); fprintf(file," refmethod : "); - utf_fprint(file,ref->referermethod->name); fputc('\n',file); + utf_fprint_printable_ascii(file,ref->referermethod->name); fputc('\n',file); fprintf(file," refmethodd: "); - utf_fprint(file,ref->referermethod->descriptor); fputc('\n',file); + utf_fprint_printable_ascii(file,ref->referermethod->descriptor); fputc('\n',file); fprintf(file," classname : "); - utf_fprint(file,ref->classref->name); fputc('\n',file); + utf_fprint_printable_ascii(file,ref->classref->name); fputc('\n',file); fprintf(file," subtypeconstraints:\n"); unresolved_subtype_set_debug_dump(&(ref->subtypeconstraints),file); } @@ -2026,17 +3072,17 @@ 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->p.classref->referer->name); fputc('\n',file); + utf_fprint_printable_ascii(file,ref->referermethod->class->name); fputc('\n',file); fprintf(file," refmethod : "); - utf_fprint(file,ref->referermethod->name); fputc('\n',file); + utf_fprint_printable_ascii(file,ref->referermethod->name); fputc('\n',file); fprintf(file," refmethodd: "); - utf_fprint(file,ref->referermethod->descriptor); fputc('\n',file); + utf_fprint_printable_ascii(file,ref->referermethod->descriptor); fputc('\n',file); fprintf(file," classname : "); - utf_fprint(file,ref->fieldref->p.classref->name); fputc('\n',file); + utf_fprint_printable_ascii(file,FIELDREF_CLASSNAME(ref->fieldref)); fputc('\n',file); fprintf(file," name : "); - utf_fprint(file,ref->fieldref->name); fputc('\n',file); + utf_fprint_printable_ascii(file,ref->fieldref->name); fputc('\n',file); fprintf(file," descriptor: "); - utf_fprint(file,ref->fieldref->descriptor); fputc('\n',file); + utf_fprint_printable_ascii(file,ref->fieldref->descriptor); fputc('\n',file); fprintf(file," parseddesc: "); descriptor_debug_print_typedesc(file,ref->fieldref->parseddesc.fd); fputc('\n',file); fprintf(file," flags : %04x\n",ref->flags); @@ -2064,17 +3110,17 @@ void unresolved_method_debug_dump(unresolved_method *ref,FILE *file) fprintf(file,"unresolved_method(%p):\n",(void *)ref); if (ref) { fprintf(file," referer : "); - utf_fprint(file,ref->methodref->p.classref->referer->name); fputc('\n',file); + utf_fprint_printable_ascii(file,ref->referermethod->class->name); fputc('\n',file); fprintf(file," refmethod : "); - utf_fprint(file,ref->referermethod->name); fputc('\n',file); + utf_fprint_printable_ascii(file,ref->referermethod->name); fputc('\n',file); fprintf(file," refmethodd: "); - utf_fprint(file,ref->referermethod->descriptor); fputc('\n',file); + utf_fprint_printable_ascii(file,ref->referermethod->descriptor); fputc('\n',file); fprintf(file," classname : "); - utf_fprint(file,ref->methodref->p.classref->name); fputc('\n',file); + utf_fprint_printable_ascii(file,METHODREF_CLASSNAME(ref->methodref)); fputc('\n',file); fprintf(file," name : "); - utf_fprint(file,ref->methodref->name); fputc('\n',file); + utf_fprint_printable_ascii(file,ref->methodref->name); fputc('\n',file); fprintf(file," descriptor: "); - utf_fprint(file,ref->methodref->descriptor); fputc('\n',file); + utf_fprint_printable_ascii(file,ref->methodref->descriptor); fputc('\n',file); fprintf(file," parseddesc: "); descriptor_debug_print_methoddesc(file,ref->methodref->parseddesc.md); fputc('\n',file); fprintf(file," flags : %04x\n",ref->flags); @@ -2086,13 +3132,13 @@ void unresolved_method_debug_dump(unresolved_method *ref,FILE *file) fprintf(file," param %d:\n",i); unresolved_subtype_set_debug_dump(ref->paramconstraints + i,file); } - } + } else { fprintf(file," (empty)\n"); } } } -#endif +#endif /* !defined(NDEBUG) */ /* * These are local overrides for various environment variables in Emacs.