+ /* first resolve the type if necessary */
+ if (!resolve_classref_or_classinfo(refmethod,typeref,mode,false,true,&(typeref.cls)))
+ return resolveFailed; /* exception */
+ if (!typeref.cls)
+ return resolveDeferred; /* be lazy */
+
+ assert(typeref.cls->state & CLASS_LINKED);
+
+ /* iterate over the set members */
+
+ for (; setp->any; ++setp) {
+ checkresult = resolve_subtype_check(refmethod,*setp,typeref,mode,error);
+#if defined(RESOLVE_VERBOSE)
+ if (checkresult != resolveSucceeded)
+ printf("SUBTYPE CHECK FAILED!\n");
+#endif
+ if (checkresult != resolveSucceeded)
+ return checkresult;
+ }
+
+ /* check succeeds */
+ return resolveSucceeded;
+}
+#endif /* defined(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;
+ resolve_result_t checkresult;
+
+ assert(ref);
+ assert(result);
+ assert(mode == resolveLazy || mode == resolveEager);
+
+ *result = NULL;
+
+#ifdef RESOLVE_VERBOSE
+ unresolved_class_debug_dump(ref,stdout);
+#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->state & CLASS_LOADED) && (cls->state & CLASS_LINKED));
+
+ /* now we check the subtype constraints */
+
+ checkresult = resolve_and_check_subtype_set(ref->referermethod,
+ &(ref->subtypeconstraints),
+ CLASSREF_OR_CLASSINFO(cls),
+ mode,
+ resolveLinkageError);
+ if (checkresult != resolveSucceeded)
+ return (bool) checkresult;
+
+ /* 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) {
+ exceptions_throw_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 */
+
+/* resolve_class_eager_no_access_check *****************************************
+
+ Resolve an unresolved class reference eagerly. The class is also linked.
+ Access rights are _not_ checked.
+
+ IN:
+ ref..............struct containing the reference
+
+ RETURN VALUE:
+ classinfo * to the class, or
+ NULL if an exception has been thrown
+
+*******************************************************************************/
+
+#ifdef ENABLE_VERIFIER
+classinfo * resolve_class_eager_no_access_check(unresolved_class *ref)
+{
+ classinfo *c;
+
+ if (!resolve_class(ref, resolveEager, false, &c))
+ return NULL;
+
+ return c;
+}
+#endif /* ENABLE_VERIFIER */
+
+/******************************************************************************/
+/* FIELD RESOLUTION */
+/******************************************************************************/
+
+/* resolve_field_verifier_checks *******************************************
+
+ Do the verifier checks necessary after field has been resolved.
+
+ IN:
+ 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
+ instanceti.......instance typeinfo, if available
+ valueti..........value typeinfo, if available
+ isstatic.........true if this is a *STATIC* instruction
+ isput............true if this is a PUT* instruction
+
+ 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_field_verifier_checks(methodinfo *refmethod,
+ constant_FMIref *fieldref,
+ classinfo *container,
+ fieldinfo *fi,
+ typeinfo *instanceti,
+ typeinfo *valueti,
+ bool isstatic,
+ bool isput)
+{
+ classinfo *declarer;
+ classinfo *referer;
+ resolve_result_t result;
+ constant_classref *fieldtyperef;
+ char *msg;
+ s4 msglen;
+ utf *u;
+
+ assert(refmethod);
+ assert(fieldref);
+ assert(container);
+ assert(fi);
+
+ /* get the classinfos and the field type */
+
+ referer = refmethod->class;
+ assert(referer);
+
+ declarer = fi->class;
+ assert(declarer);
+ assert(referer->state & CLASS_LINKED);
+
+ fieldtyperef = fieldref->parseddesc.fd->classref;
+
+ /* 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 */
+ exceptions_throw_incompatibleclasschangeerror(declarer,
+ (fi->flags & ACC_STATIC)
+ ? "static field accessed via instance"
+ : "instance field accessed without instance");
+
+ return resolveFailed;
+ }
+
+ /* check access rights */
+
+ if (!access_is_accessible_member(referer,declarer,fi->flags)) {
+ msglen =
+ utf_bytes(declarer->name) +
+ utf_bytes(fi->name) +
+ utf_bytes(referer->name) +
+ 100;
+
+ msg = MNEW(char, msglen);
+
+ strcpy(msg, "field is not accessible (");
+ utf_cat_classname(msg, declarer->name);
+ strcat(msg, ".");
+ utf_cat(msg, fi->name);
+ strcat(msg, " from ");
+ utf_cat_classname(msg, referer->name);
+ strcat(msg, ")");
+
+ u = utf_new_char(msg);
+
+ MFREE(msg, char, msglen);
+
+ exceptions_throw_illegalaccessexception(u);
+
+ return resolveFailed; /* exception */
+ }
+
+ /* for non-static methods we have to check the constraints on the */
+ /* instance type */
+
+ if (instanceti) {
+ typeinfo *insttip;
+ typeinfo tinfo;
+
+ /* The instanceslot must contain a reference to a non-array type */
+
+ if (!TYPEINFO_IS_REFERENCE(*instanceti)) {
+ exceptions_throw_verifyerror(refmethod, "illegal instruction: field access on non-reference");
+ return resolveFailed;
+ }
+ if (TYPEINFO_IS_ARRAY(*instanceti)) {
+ exceptions_throw_verifyerror(refmethod, "illegal instruction: field access on array");
+ return resolveFailed;
+ }
+
+ if (isput && TYPEINFO_IS_NEWOBJECT(*instanceti))
+ {
+ /* 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(*instanceti);
+
+ if (ins != NULL) {
+ exceptions_throw_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 = instanceti;
+ }
+
+ 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,
+ instanceti,
+ CLASSREF_OR_CLASSINFO(referer),
+ resolveIllegalAccessError);
+ if (result != resolveSucceeded)
+ return result;
+ }
+
+ }
+
+ /* for PUT* instructions we have to check the constraints on the value type */
+
+ if (valueti) {
+ assert(fieldtyperef);
+
+ /* check subtype constraints */
+ result = resolve_lazy_subtype_checks(refmethod,
+ valueti,
+ 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 constraint on instance? */
+
+ /* everything ok */
+ return resolveSucceeded;
+}
+#endif /* defined(ENABLE_VERIFIER) */
+
+/* resolve_field_lazy **********************************************************
+
+ Resolve an unresolved field reference lazily
+
+ NOTE: This function does NOT do any verification checks. In case of a
+ successful resolution, you must call resolve_field_verifier_checks
+ in order to perform the necessary checks!
+
+ IN:
+ refmethod........the referer method
+ fieldref.........the field reference
+
+ 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 resolve_field_lazy(methodinfo *refmethod,
+ constant_FMIref *fieldref)
+{
+ classinfo *referer;
+ classinfo *container;
+ fieldinfo *fi;
+
+ assert(refmethod);
+
+ /* the class containing the reference */
+
+ referer = refmethod->class;
+ assert(referer);
+
+ /* check if the field itself is already resolved */
+
+ if (IS_FMIREF_RESOLVED(fieldref))
+ return resolveSucceeded;
+
+ /* 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.) */
+
+ exceptions_clear_exception();
+ return resolveDeferred; /* be lazy */
+ }
+
+ /* cache the result of the resolution */
+
+ fieldref->p.field = fi;
+
+ /* 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,stdout);
+#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
+ printf(" 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.) */
+
+ exceptions_clear_exception();
+ return true; /* be lazy */
+ }
+
+ return false; /* exception */
+ }
+
+ /* cache the result of the resolution */
+ ref->fieldref->p.field = fi;
+
+resolved_the_field:
+
+#ifdef ENABLE_VERIFIER
+ /* Checking opt_verify is ok here, because the NULL iptr guarantees */
+ /* that no missing parts of an instruction will be accessed. */
+ if (opt_verify) {
+ checkresult = resolve_field_verifier_checks(
+ ref->referermethod,
+ ref->fieldref,
+ container,
+ fi,
+ NULL, /* instanceti, handled by constraints below */
+ NULL, /* valueti, handled by constraints below */
+ (ref->flags & RESOLVE_STATIC) != 0, /* isstatic */
+ (ref->flags & RESOLVE_PUTFIELD) != 0 /* isput */);
+
+ 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(referer->state & CLASS_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 ((referer != declarer) && (mi->name != utf_init)) {
+ /* check that declarer is a super class of the current class */
+
+ if (!class_issubclass(referer,declarer)) {
+ exceptions_throw_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
+ 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,
+ methodinfo *mi,
+ bool invokestatic)
+{
+ classinfo *declarer;
+ classinfo *referer;
+ char *msg;
+ s4 msglen;
+ utf *u;
+
+ assert(refmethod);
+ assert(methodref);
+ assert(mi);
+
+#ifdef RESOLVE_VERBOSE
+ printf("resolve_method_verifier_checks\n");
+ printf(" flags: %02x\n",mi->flags);
+#endif
+
+ /* get the classinfos and the method descriptor */
+
+ referer = refmethod->class;
+ assert(referer);
+
+ declarer = mi->class;
+ assert(declarer);
+
+ /* check static */
+
+ if (((mi->flags & ACC_STATIC) != 0) != (invokestatic != false)) {
+ /* a static method is accessed via an instance, or vice versa */
+ exceptions_throw_incompatibleclasschangeerror(declarer,
+ (mi->flags & ACC_STATIC)
+ ? "static method called via instance"
+ : "instance method called without instance");
+
+ return resolveFailed;
+ }
+
+ /* check access rights */
+
+ if (!access_is_accessible_member(referer,declarer,mi->flags)) {
+ /* 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;
+
+ msg = MNEW(char, msglen);
+
+ strcpy(msg, "method is not accessible (");
+ utf_cat_classname(msg, declarer->name);
+ strcat(msg, ".");
+ utf_cat(msg, mi->name);
+ utf_cat(msg, mi->descriptor);
+ strcat(msg, " from ");
+ utf_cat_classname(msg, referer->name);
+ strcat(msg, ")");
+
+ u = utf_new_char(msg);
+
+ MFREE(msg, char, msglen);
+
+ exceptions_throw_illegalaccessexception(u);
+
+ return resolveFailed; /* exception */
+ }
+
+ /* everything ok */
+
+ return resolveSucceeded;
+}
+#endif /* defined(ENABLE_VERIFIER) */
+
+
+/* resolve_method_instance_type_checks *****************************************
+
+ Check the instance type of a method invocation.
+
+ IN:
+ refmethod........the method containing the reference
+ mi...............the methodinfo of the resolved method
+ instanceti.......typeinfo of the instance slot
+ invokespecial....true if the method is invoked by INVOKESPECIAL
+
+ 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_instance_type_checks(methodinfo *refmethod,
+ methodinfo *mi,
+ typeinfo *instanceti,
+ bool invokespecial)
+{
+ typeinfo tinfo;
+ typeinfo *tip;
+ resolve_result_t result;
+
+ if (invokespecial && TYPEINFO_IS_NEWOBJECT(*instanceti))
+ { /* XXX clean up */
+ instruction *ins = (instruction *) TYPEINFO_NEWOBJECT_INSTRUCTION(*instanceti);
+ classref_or_classinfo initclass = (ins) ? ins[-1].sx.val.c
+ : CLASSREF_OR_CLASSINFO(refmethod->class);
+ tip = &tinfo;
+ if (!typeinfo_init_class(tip, initclass))
+ return false;
+ }
+ else {
+ tip = instanceti;
+ }
+
+ result = resolve_lazy_subtype_checks(refmethod,
+ tip,
+ CLASSREF_OR_CLASSINFO(mi->class),
+ resolveLinkageError);
+ if (result != resolveSucceeded)
+ return result;
+
+ /* check protected access */
+
+ /* XXX use other `declarer` than mi->class? */
+ if (((mi->flags & ACC_PROTECTED) != 0)
+ && !SAME_PACKAGE(mi->class, refmethod->class))
+ {
+ result = resolve_lazy_subtype_checks(refmethod,
+ tip,
+ CLASSREF_OR_CLASSINFO(refmethod->class),
+ resolveIllegalAccessError);
+ if (result != resolveSucceeded)
+ return result;
+ }
+
+ /* everything ok */
+
+ return resolveSucceeded;
+}
+#endif /* defined(ENABLE_VERIFIER) */
+
+
+/* resolve_method_param_type_checks ********************************************
+
+ Check non-instance parameter types of a method invocation.
+
+ IN:
+ jd...............jitdata of the method doing the call
+ refmethod........the method containing the reference
+ iptr.............the invoke instruction
+ 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_param_type_checks(jitdata *jd,
+ methodinfo *refmethod,
+ instruction *iptr,
+ methodinfo *mi,
+ bool invokestatic)
+{
+ varinfo *param;
+ resolve_result_t result;
+ methoddesc *md;
+ typedesc *paramtypes;
+ s4 type;
+ s4 instancecount;
+ s4 i;
+
+ assert(jd);
+
+ instancecount = (invokestatic) ? 0 : 1;
+
+ /* check subtype constraints for TYPE_ADR parameters */
+
+ md = mi->parseddesc;
+ paramtypes = md->paramtypes;
+
+ for (i = md->paramcount-1-instancecount; i>=0; --i) {
+ param = VAR(iptr->sx.s23.s2.args[i+instancecount]);
+ 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;
+ }
+ }
+
+ /* everything ok */
+
+ return resolveSucceeded;
+}
+#endif /* defined(ENABLE_VERIFIER) */
+
+
+/* resolve_method_param_type_checks_stackbased *********************************
+
+ Check non-instance parameter types of a method invocation.
+
+ IN:
+ refmethod........the method containing the reference
+ mi...............the methodinfo of the resolved method
+ invokestatic.....true if the method is invoked by INVOKESTATIC
+ stack............TOS before the INVOKE instruction
+
+ 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_param_type_checks_stackbased(
+ methodinfo *refmethod,
+ methodinfo *mi,
+ bool invokestatic,
+ typedescriptor *stack)
+{
+ typedescriptor *param;
+ resolve_result_t result;
+ methoddesc *md;
+ typedesc *paramtypes;
+ s4 type;
+ s4 instancecount;
+ s4 i;
+
+ instancecount = (invokestatic) ? 0 : 1;
+
+ /* check subtype constraints for TYPE_ADR parameters */
+
+ md = mi->parseddesc;
+ paramtypes = md->paramtypes;
+
+ param = stack - (md->paramslots - 1 - instancecount);
+
+ for (i = instancecount; i < md->paramcount; ++i) {
+ type = md->paramtypes[i].type;
+
+ assert(type == param->type);
+
+ if (type == TYPE_ADR) {
+ result = resolve_lazy_subtype_checks(refmethod,
+ &(param->typeinfo),
+ CLASSREF_OR_CLASSINFO(paramtypes[i].classref),
+ resolveLinkageError);
+ if (result != resolveSucceeded)
+ return result;
+ }
+
+ param += (IS_2_WORD_TYPE(type)) ? 2 : 1;
+ }
+
+ /* everything ok */
+
+ return resolveSucceeded;
+}
+#endif /* defined(ENABLE_VERIFIER) */
+
+
+/* resolve_method_loading_constraints ******************************************
+
+ Impose loading constraints on the parameters and return type of the
+ given method.
+
+ IN:
+ referer..........the class refering to the method
+ mi...............the method
+
+ RETURN VALUE:
+ true................everything ok
+ false...............an exception has been thrown
+
+*******************************************************************************/
+
+#if defined(ENABLE_VERIFIER)
+bool resolve_method_loading_constraints(classinfo *referer,
+ methodinfo *mi)
+{
+ methoddesc *md;
+ typedesc *paramtypes;
+ utf *name;
+ s4 i;
+ s4 instancecount;
+
+ /* impose loading constraints on parameters (including instance) */
+
+ md = mi->parseddesc;
+ paramtypes = md->paramtypes;
+ instancecount = (mi->flags & ACC_STATIC) / ACC_STATIC;
+
+ for (i = 0; i < md->paramcount; i++) {
+ if (i < instancecount || paramtypes[i].type == TYPE_ADR) {
+ 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 = mi->class->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,
+ mi->class->classloader, name))
+ 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,
+ mi->class->classloader,
+ md->returntype.classref->name))
+ return false; /* exception */
+ }
+
+ /* everything ok */
+
+ return true;
+}
+#endif /* defined(ENABLE_VERIFIER) */
+
+
+/* resolve_method_lazy *********************************************************
+
+ Resolve an unresolved method reference lazily
+
+ NOTE: This function does NOT do any verification checks. In case of a
+ successful resolution, you must call resolve_method_verifier_checks
+ in order to perform the necessary checks!
+
+ IN:
+ refmethod........the referer method
+ methodref........the method reference
+ invokespecial....true if this is an INVOKESPECIAL instruction
+
+ 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 resolve_method_lazy(methodinfo *refmethod,
+ constant_FMIref *methodref,
+ bool invokespecial)
+{
+ classinfo *referer;
+ classinfo *container;
+ methodinfo *mi;
+
+ assert(refmethod);
+
+#ifdef RESOLVE_VERBOSE
+ printf("resolve_method_lazy\n");
+#endif
+
+ /* the class containing the reference */
+
+ referer = refmethod->class;
+ assert(referer);
+
+ /* check if the method itself is already resolved */
+
+ if (IS_FMIREF_RESOLVED(methodref))
+ return resolveSucceeded;
+
+ /* 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.) */
+
+ exceptions_clear_exception();
+ return resolveDeferred; /* be lazy */
+ }
+
+ if (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;
+
+ /* succeed */
+
+ return resolveSucceeded;
+}
+
+/* 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;
+ classinfo *declarer;
+ methodinfo *mi;
+ typedesc *paramtypes;
+ int instancecount;
+ int i;
+ resolve_result_t checkresult;
+
+ assert(ref);
+ assert(result);
+ assert(mode == resolveLazy || mode == resolveEager);
+
+#ifdef RESOLVE_VERBOSE
+ unresolved_method_debug_dump(ref,stdout);
+#endif
+
+ *result = NULL;
+
+ /* the class containing the reference */
+
+ referer = ref->referermethod->class;
+ assert(referer);
+
+ /* 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))