--- /dev/null
+ /* src/vm/class.cpp - class related functions
+
+ Copyright (C) 1996-2005, 2006, 2007, 2008
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+ This file is part of CACAO.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+ */
+
+
+ #include "config.h"
+
+ #include <assert.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+
+ #include "vm/types.h"
+
+ #include "arch.h"
+
+ #include "mm/memory.h"
+
+ #include "native/llni.h"
+
+ #include "threads/lock.hpp"
+ #include "threads/mutex.hpp"
+
+ #include "toolbox/logging.h"
+
+ #include "vm/array.hpp"
+ #include "vm/jit/builtin.hpp"
+ #include "vm/class.hpp"
+ #include "vm/classcache.h"
+ #include "vm/exceptions.hpp"
+ #include "vm/global.h"
+ #include "vm/globals.hpp"
+ #include "vm/javaobjects.hpp"
++#include "vm/jit/jitcache.hpp"
+ #include "vm/linker.h"
+ #include "vm/loader.hpp"
+ #include "vm/options.h"
+ #include "vm/resolve.hpp"
+
+ #if defined(ENABLE_STATISTICS)
+ # include "vm/statistics.h"
+ #endif
+
+ #include "vm/suck.hpp"
+ #include "vm/utf8.h"
+
+ #include "vm/jit/asmpart.h"
+
+
+ /* class_set_packagename *******************************************************
+
+ Derive the package name from the class name and store it in the
+ struct.
+
+ An internal package name consists of the package name plus the
+ trailing '/', e.g. "java/lang/".
+
+ For classes in the unnamed package, the package name is set to
+ NULL.
+
+ *******************************************************************************/
+
+ void class_set_packagename(classinfo *c)
+ {
+ char *p;
+ char *start;
+
+ p = UTF_END(c->name) - 1;
+ start = c->name->text;
+
+ if (c->name->text[0] == '[') {
+ /* Set packagename of arrays to the element's package. */
+
+ for (; *start == '['; start++);
+
+ /* Skip the 'L' in arrays of references. */
+
+ if (*start == 'L')
+ start++;
+ }
+
+ /* Search for last '/'. */
+
+ for (; (p > start) && (*p != '/'); --p);
+
+ /* If we found a '/' we set the package name plus the trailing
+ '/'. Otherwise we set the packagename to NULL. */
+
+ if (p > start)
+ c->packagename = utf_new(start, p - start + 1);
+ else
+ c->packagename = NULL;
+ }
+
+
+ /* class_create_classinfo ******************************************************
+
+ Create a new classinfo struct. The class name is set to the given utf *,
+ most other fields are initialized to zero.
+
+ Note: classname may be NULL. In this case a not-yet-named classinfo is
+ created. The name must be filled in later and class_set_packagename
+ must be called after that.
+
+ *******************************************************************************/
+
+ classinfo *class_create_classinfo(utf *classname)
+ {
+ classinfo *c;
+
+ #if defined(ENABLE_STATISTICS)
+ if (opt_stat)
+ size_classinfo += sizeof(classinfo);
+ #endif
+
+ /* we use a safe name for temporarily unnamed classes */
+
+ if (classname == NULL)
+ classname = utf_not_named_yet;
+
+ #if !defined(NDEBUG)
+ if (initverbose)
+ log_message_utf("Creating class: ", classname);
+ #endif
+
+ #if !defined(ENABLE_GC_BOEHM)
+ c = (classinfo *) heap_alloc_uncollectable(sizeof(classinfo));
+ /*c = NEW(classinfo);
+ MZERO(c, classinfo, 1);*/
+ #else
+ c = GCNEW_UNCOLLECTABLE(classinfo, 1);
+ /* GCNEW_UNCOLLECTABLE clears the allocated memory */
+ #endif
+
+ c->name = classname;
+
+ /* Set the header.vftbl of all loaded classes to the one of
+ java.lang.Class, so Java code can use a class as object. */
+
+ if (class_java_lang_Class != NULL)
+ if (class_java_lang_Class->vftbl != NULL)
+ c->object.header.vftbl = class_java_lang_Class->vftbl;
+
+ #if defined(ENABLE_JAVASE)
+ /* check if the class is a reference class and flag it */
+
+ if (classname == utf_java_lang_ref_SoftReference) {
+ c->flags |= ACC_CLASS_REFERENCE_SOFT;
+ }
+ else if (classname == utf_java_lang_ref_WeakReference) {
+ c->flags |= ACC_CLASS_REFERENCE_WEAK;
+ }
+ else if (classname == utf_java_lang_ref_PhantomReference) {
+ c->flags |= ACC_CLASS_REFERENCE_PHANTOM;
+ }
+ #endif
+
+ if (classname != utf_not_named_yet)
+ class_set_packagename(c);
++#if defined (ENABLE_JITCACHE)
++ c->cache_file_fd = 0;
++#endif
+
+ c->object.header.lockword.init();
+
+ return c;
+ }
+
+
+ /* class_postset_header_vftbl **************************************************
+
+ Set the header.vftbl of all classes created before java.lang.Class
+ was linked. This is necessary that Java code can use a class as
+ object.
+
+ *******************************************************************************/
+
+ void class_postset_header_vftbl(void)
+ {
+ classinfo *c;
+ u4 slot;
+ classcache_name_entry *nmen;
+ classcache_class_entry *clsen;
+
+ assert(class_java_lang_Class);
+
+ for (slot = 0; slot < hashtable_classcache.size; slot++) {
+ nmen = (classcache_name_entry *) hashtable_classcache.ptr[slot];
+
+ for (; nmen; nmen = nmen->hashlink) {
+ /* iterate over all class entries */
+
+ for (clsen = nmen->classes; clsen; clsen = clsen->next) {
+ c = clsen->classobj;
+
+ /* now set the the vftbl */
+
+ if (c->object.header.vftbl == NULL)
+ c->object.header.vftbl = class_java_lang_Class->vftbl;
+ }
+ }
+ }
+ }
+
+ /* class_define ****************************************************************
+
+ Calls the loader and defines a class in the VM.
+
+ *******************************************************************************/
+
+ classinfo *class_define(utf *name, classloader_t *cl, int32_t length, uint8_t *data, java_handle_t *pd)
+ {
+ classinfo *c;
+ classinfo *r;
+ classbuffer *cb;
+
+ if (name != NULL) {
+ /* check if this class has already been defined */
+
+ c = classcache_lookup_defined_or_initiated(cl, name);
+
+ if (c != NULL) {
+ exceptions_throw_linkageerror("duplicate class definition: ", c);
+ return NULL;
+ }
+ }
+
+ /* create a new classinfo struct */
+
+ c = class_create_classinfo(name);
+
+ #if defined(ENABLE_STATISTICS)
+ /* measure time */
+
+ if (opt_getloadingtime)
+ loadingtime_start();
+ #endif
+
+ /* build a classbuffer with the given data */
+
+ cb = NEW(classbuffer);
+
+ cb->clazz = c;
+ cb->size = length;
+ cb->data = data;
+ cb->pos = cb->data;
+
+ /* preset the defining classloader */
+
+ c->classloader = cl;
+
+ /* load the class from this buffer */
+
+ r = load_class_from_classbuffer(cb);
+
+ /* free memory */
+
+ FREE(cb, classbuffer);
+
+ #if defined(ENABLE_STATISTICS)
+ /* measure time */
+
+ if (opt_getloadingtime)
+ loadingtime_stop();
+ #endif
+
+ if (r == NULL) {
+ /* If return value is NULL, we had a problem and the class is
+ not loaded. Now free the allocated memory, otherwise we
+ could run into a DOS. */
+
+ class_free(c);
+
+ return NULL;
+ }
+
+ #if defined(ENABLE_JAVASE)
+ # if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
+ /* Store the protection domain. */
+
+ c->protectiondomain = pd;
+ # endif
+ #endif
+
+ /* Store the newly defined class in the class cache. This call
+ also checks whether a class of the same name has already been
+ defined by the same defining loader, and if so, replaces the
+ newly created class by the one defined earlier. */
+
+ /* Important: The classinfo given to classcache_store must be
+ fully prepared because another thread may return
+ this pointer after the lookup at to top of this
+ function directly after the class cache lock has
+ been released. */
+
+ c = classcache_store(cl, c, true);
+
+ return c;
+ }
+
+
+ /* class_load_attribute_sourcefile *********************************************
+
+ SourceFile_attribute {
+ u2 attribute_name_index;
+ u4 attribute_length;
+ u2 sourcefile_index;
+ }
+
+ *******************************************************************************/
+
+ static bool class_load_attribute_sourcefile(classbuffer *cb)
+ {
+ classinfo *c;
+ u4 attribute_length;
+ u2 sourcefile_index;
+ utf *sourcefile;
+
+ /* get classinfo */
+
+ c = cb->clazz;
+
+ /* check buffer size */
+
+ if (!suck_check_classbuffer_size(cb, 4 + 2))
+ return false;
+
+ /* check attribute length */
+
+ attribute_length = suck_u4(cb);
+
+ if (attribute_length != 2) {
+ exceptions_throw_classformaterror(c, "Wrong size for VALUE attribute");
+ return false;
+ }
+
+ /* there can be no more than one SourceFile attribute */
+
+ if (c->sourcefile != NULL) {
+ exceptions_throw_classformaterror(c, "Multiple SourceFile attributes");
+ return false;
+ }
+
+ /* get sourcefile */
+
+ sourcefile_index = suck_u2(cb);
+ sourcefile = (utf*) class_getconstant(c, sourcefile_index, CONSTANT_Utf8);
+
+ if (sourcefile == NULL)
+ return false;
+
+ /* store sourcefile */
+
+ c->sourcefile = sourcefile;
+
+ return true;
+ }
+
+
+ /* class_load_attribute_enclosingmethod ****************************************
+
+ EnclosingMethod_attribute {
+ u2 attribute_name_index;
+ u4 attribute_length;
+ u2 class_index;
+ u2 method_index;
+ }
+
+ *******************************************************************************/
+
+ #if defined(ENABLE_JAVASE)
+ static bool class_load_attribute_enclosingmethod(classbuffer *cb)
+ {
+ classinfo *c;
+ u4 attribute_length;
+ u2 class_index;
+ u2 method_index;
+ classref_or_classinfo cr;
+ constant_nameandtype *cn;
+
+ /* get classinfo */
+
+ c = cb->clazz;
+
+ /* check buffer size */
+
+ if (!suck_check_classbuffer_size(cb, 4 + 2 + 2))
+ return false;
+
+ /* check attribute length */
+
+ attribute_length = suck_u4(cb);
+
+ if (attribute_length != 4) {
+ exceptions_throw_classformaterror(c, "Wrong size for VALUE attribute");
+ return false;
+ }
+
+ /* there can be no more than one EnclosingMethod attribute */
+
+ if (c->enclosingmethod != NULL) {
+ exceptions_throw_classformaterror(c, "Multiple EnclosingMethod attributes");
+ return false;
+ }
+
+ /* get class index */
+
+ class_index = suck_u2(cb);
+ cr.ref = (constant_classref*) innerclass_getconstant(c, class_index, CONSTANT_Class);
+
+ /* get method index */
+
+ method_index = suck_u2(cb);
+ cn = (constant_nameandtype*) innerclass_getconstant(c, method_index, CONSTANT_NameAndType);
+
+ /* store info in classinfo */
+
+ c->enclosingclass.any = cr.any;
+ c->enclosingmethod = cn;
+
+ return true;
+ }
+ #endif /* defined(ENABLE_JAVASE) */
+
+
+ /* class_load_attributes *******************************************************
+
+ Read attributes from ClassFile.
+
+ attribute_info {
+ u2 attribute_name_index;
+ u4 attribute_length;
+ u1 info[attribute_length];
+ }
+
+ InnerClasses_attribute {
+ u2 attribute_name_index;
+ u4 attribute_length;
+ }
+
+ *******************************************************************************/
+
+ bool class_load_attributes(classbuffer *cb)
+ {
+ classinfo *c;
+ uint16_t attributes_count;
+ uint16_t attribute_name_index;
+ utf *attribute_name;
+ innerclassinfo *info;
+ classref_or_classinfo inner;
+ classref_or_classinfo outer;
+ utf *name;
+ uint16_t flags;
+ int i, j;
+
+ c = cb->clazz;
+
+ /* get attributes count */
+
+ if (!suck_check_classbuffer_size(cb, 2))
+ return false;
+
+ attributes_count = suck_u2(cb);
+
+ for (i = 0; i < attributes_count; i++) {
+ /* get attribute name */
+
+ if (!suck_check_classbuffer_size(cb, 2))
+ return false;
+
+ attribute_name_index = suck_u2(cb);
+ attribute_name =
+ (utf*) class_getconstant(c, attribute_name_index, CONSTANT_Utf8);
+
+ if (attribute_name == NULL)
+ return false;
+
+ if (attribute_name == utf_InnerClasses) {
+ /* InnerClasses */
+
+ if (c->innerclass != NULL) {
+ exceptions_throw_classformaterror(c, "Multiple InnerClasses attributes");
+ return false;
+ }
+
+ if (!suck_check_classbuffer_size(cb, 4 + 2))
+ return false;
+
+ /* skip attribute length */
+ suck_u4(cb);
+
+ /* number of records */
+ c->innerclasscount = suck_u2(cb);
+
+ if (!suck_check_classbuffer_size(cb, (2 + 2 + 2 + 2) * c->innerclasscount))
+ return false;
+
+ /* allocate memory for innerclass structure */
+ c->innerclass = MNEW(innerclassinfo, c->innerclasscount);
+
+ for (j = 0; j < c->innerclasscount; j++) {
+ /* The innerclass structure contains a class with an encoded
+ name, its defining scope, its simple name and a bitmask of
+ the access flags. */
+
+ info = c->innerclass + j;
+
+ inner.ref = (constant_classref*) innerclass_getconstant(c, suck_u2(cb), CONSTANT_Class);
+ outer.ref = (constant_classref*) innerclass_getconstant(c, suck_u2(cb), CONSTANT_Class);
+ name = (utf*) innerclass_getconstant(c, suck_u2(cb), CONSTANT_Utf8);
+ flags = suck_u2(cb);
+
+ /* If the current inner-class is the currently loaded
+ class check for some special flags. */
+
+ if (inner.ref->name == c->name) {
+ /* If an inner-class is not a member, its
+ outer-class is NULL. */
+
+ if (outer.ref != NULL) {
+ c->flags |= ACC_CLASS_MEMBER;
+
+ /* A member class doesn't have an
+ EnclosingMethod attribute, so set the
+ enclosing-class to be the same as the
+ declaring-class. */
+
+ c->declaringclass = outer;
+ c->enclosingclass = outer;
+ }
+
+ /* If an inner-class is anonymous, its name is
+ NULL. */
+
+ if (name == NULL)
+ c->flags |= ACC_CLASS_ANONYMOUS;
+ }
+
+ info->inner_class = inner;
+ info->outer_class = outer;
+ info->name = name;
+ info->flags = flags;
+ }
+ }
+ else if (attribute_name == utf_SourceFile) {
+ /* SourceFile */
+
+ if (!class_load_attribute_sourcefile(cb))
+ return false;
+ }
+ #if defined(ENABLE_JAVASE)
+ else if (attribute_name == utf_EnclosingMethod) {
+ /* EnclosingMethod */
+
+ if (!class_load_attribute_enclosingmethod(cb))
+ return false;
+ }
+ else if (attribute_name == utf_Signature) {
+ /* Signature */
+
+ if (!loader_load_attribute_signature(cb, &(c->signature)))
+ return false;
+ }
+ #endif
+
+ #if defined(ENABLE_ANNOTATIONS)
+ else if (attribute_name == utf_RuntimeVisibleAnnotations) {
+ /* RuntimeVisibleAnnotations */
+ if (!annotation_load_class_attribute_runtimevisibleannotations(cb))
+ return false;
+ }
+ else if (attribute_name == utf_RuntimeInvisibleAnnotations) {
+ /* RuntimeInvisibleAnnotations */
+ if (!annotation_load_class_attribute_runtimeinvisibleannotations(cb))
+ return false;
+ }
+ #endif
+
+ else {
+ /* unknown attribute */
+
+ if (!loader_skip_attribute_body(cb))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ /* class_freepool **************************************************************
+
+ Frees all resources used by this classes Constant Pool.
+
+ *******************************************************************************/
+
+ static void class_freecpool(classinfo *c)
+ {
+ u4 idx;
+ u4 tag;
+ void* info;
+
+ if (c->cptags && c->cpinfos) {
+ for (idx = 0; idx < c->cpcount; idx++) {
+ tag = c->cptags[idx];
+ info = c->cpinfos[idx];
+
+ if (info != NULL) {
+ switch (tag) {
+ case CONSTANT_Fieldref:
+ case CONSTANT_Methodref:
+ case CONSTANT_InterfaceMethodref:
+ FREE(info, constant_FMIref);
+ break;
+ case CONSTANT_Integer:
+ FREE(info, constant_integer);
+ break;
+ case CONSTANT_Float:
+ FREE(info, constant_float);
+ break;
+ case CONSTANT_Long:
+ FREE(info, constant_long);
+ break;
+ case CONSTANT_Double:
+ FREE(info, constant_double);
+ break;
+ case CONSTANT_NameAndType:
+ FREE(info, constant_nameandtype);
+ break;
+ }
+ }
+ }
+ }
+
+ if (c->cptags)
+ MFREE(c->cptags, u1, c->cpcount);
+
+ if (c->cpinfos)
+ MFREE(c->cpinfos, void*, c->cpcount);
+ }
+
+
+ /* class_getconstant ***********************************************************
+
+ Retrieves the value at position 'pos' of the constantpool of a
+ class. If the type of the value is other than 'ctype', an error is
+ thrown.
+
+ *******************************************************************************/
+
+ void* class_getconstant(classinfo *c, u4 pos, u4 ctype)
+ {
+ /* check index and type of constantpool entry */
+ /* (pos == 0 is caught by type comparison) */
+
+ if ((pos >= c->cpcount) || (c->cptags[pos] != ctype)) {
+ exceptions_throw_classformaterror(c, "Illegal constant pool index");
+ return NULL;
+ }
+
+ return c->cpinfos[pos];
+ }
+
+
+ /* innerclass_getconstant ******************************************************
+
+ Like class_getconstant, but if cptags is ZERO, null is returned.
+
+ *******************************************************************************/
+
+ void* innerclass_getconstant(classinfo *c, u4 pos, u4 ctype)
+ {
+ /* invalid position in constantpool */
+
+ if (pos >= c->cpcount) {
+ exceptions_throw_classformaterror(c, "Illegal constant pool index");
+ return NULL;
+ }
+
+ /* constantpool entry of type 0 */
+
+ if (c->cptags[pos] == 0)
+ return NULL;
+
+ /* check type of constantpool entry */
+
+ if (c->cptags[pos] != ctype) {
+ exceptions_throw_classformaterror(c, "Illegal constant pool index");
+ return NULL;
+ }
+
+ return c->cpinfos[pos];
+ }
+
+
+ /* class_free ******************************************************************
+
+ Frees all resources used by the class.
+
+ *******************************************************************************/
+
+ void class_free(classinfo *c)
+ {
+ s4 i;
+ vftbl_t *v;
+
++#if defined(ENABLE_JITCACHE)
++/* TODO: Find a way around the linker problem */
++/* jitcache_freeclass(c);*/
++#endif
++
+ class_freecpool(c);
+
+ if (c->interfaces != NULL)
+ MFREE(c->interfaces, classinfo*, c->interfacescount);
+
+ if (c->fields) {
+ for (i = 0; i < c->fieldscount; i++)
+ field_free(&(c->fields[i]));
+ MFREE(c->fields, fieldinfo, c->fieldscount);
+ }
+
+ if (c->methods) {
+ for (i = 0; i < c->methodscount; i++)
+ method_free(&(c->methods[i]));
+ MFREE(c->methods, methodinfo, c->methodscount);
+ }
+
+ if ((v = c->vftbl) != NULL) {
+ if (v->arraydesc)
+ mem_free(v->arraydesc,sizeof(arraydescriptor));
+
+ for (i = 0; i < v->interfacetablelength; i++) {
+ MFREE(v->interfacetable[-i], methodptr, v->interfacevftbllength[i]);
+ }
+ MFREE(v->interfacevftbllength, s4, v->interfacetablelength);
+
+ i = sizeof(vftbl_t) + sizeof(methodptr) * (v->vftbllength - 1) +
+ sizeof(methodptr*) * (v->interfacetablelength -
+ (v->interfacetablelength > 0));
+ v = (vftbl_t*) (((methodptr*) v) -
+ (v->interfacetablelength - 1) * (v->interfacetablelength > 1));
+ mem_free(v, i);
+ }
+
+ if (c->innerclass)
+ MFREE(c->innerclass, innerclassinfo, c->innerclasscount);
+
+ /* if (c->classvftbl)
+ mem_free(c->header.vftbl, sizeof(vftbl) + sizeof(methodptr)*(c->vftbl->vftbllength-1)); */
+
+ /* GCFREE(c); */
+ }
+
+
+ /* get_array_class *************************************************************
+
+ Returns the array class with the given name for the given
+ classloader, or NULL if an exception occurred.
+
+ Note: This function does eager loading.
+
+ *******************************************************************************/
+
+ static classinfo *get_array_class(utf *name,classloader_t *initloader,
+ classloader_t *defloader,bool link)
+ {
+ classinfo *c;
+
+ /* lookup this class in the classcache */
+ c = classcache_lookup(initloader,name);
+ if (!c)
+ c = classcache_lookup_defined(defloader,name);
+
+ if (!c) {
+ /* we have to create it */
+ c = class_create_classinfo(name);
+ c = load_newly_created_array(c,initloader);
+ if (c == NULL)
+ return NULL;
+ }
+
+ assert(c);
+ assert(c->state & CLASS_LOADED);
+ assert(c->classloader == defloader);
+
+ if (link && !(c->state & CLASS_LINKED))
+ if (!link_class(c))
+ return NULL;
+
+ assert(!link || (c->state & CLASS_LINKED));
+
+ return c;
+ }
+
+
+ /* class_array_of **************************************************************
+
+ Returns an array class with the given component class. The array
+ class is dynamically created if neccessary.
+
+ *******************************************************************************/
+
+ classinfo *class_array_of(classinfo *component, bool link)
+ {
+ classloader_t *cl;
+ s4 namelen;
+ char *namebuf;
+ utf *u;
+ classinfo *c;
+
+ cl = component->classloader;
+
+ /* Assemble the array class name */
+ namelen = component->name->blength;
+
+ if (component->name->text[0] == '[') {
+ /* the component is itself an array */
+ namebuf = MNEW(char, namelen + 1);
+ namebuf[0] = '[';
+ MCOPY(namebuf + 1, component->name->text, char, namelen);
+ namelen++;
+ }
+ else {
+ /* the component is a non-array class */
+ namebuf = MNEW(char, namelen + 3);
+ namebuf[0] = '[';
+ namebuf[1] = 'L';
+ MCOPY(namebuf + 2, component->name->text, char, namelen);
+ namebuf[2 + namelen] = ';';
+ namelen += 3;
+ }
+
+ u = utf_new(namebuf, namelen);
+
+ MFREE(namebuf, char, namelen);
+
+ c = get_array_class(u, cl, cl, link);
+
+ return c;
+ }
+
+
+ /* class_multiarray_of *********************************************************
+
+ Returns an array class with the given dimension and element class.
+ The array class is dynamically created if neccessary.
+
+ *******************************************************************************/
+
+ classinfo *class_multiarray_of(s4 dim, classinfo *element, bool link)
+ {
+ s4 namelen;
+ char *namebuf;
+ classinfo *c;
+
+ if (dim < 1) {
+ log_text("Invalid array dimension requested");
+ assert(0);
+ }
+
+ /* Assemble the array class name */
+ namelen = element->name->blength;
+
+ if (element->name->text[0] == '[') {
+ /* the element is itself an array */
+ namebuf = MNEW(char, namelen + dim);
+ memcpy(namebuf + dim, element->name->text, namelen);
+ namelen += dim;
+ }
+ else {
+ /* the element is a non-array class */
+ namebuf = MNEW(char, namelen + 2 + dim);
+ namebuf[dim] = 'L';
+ memcpy(namebuf + dim + 1, element->name->text, namelen);
+ namelen += (2 + dim);
+ namebuf[namelen - 1] = ';';
+ }
+ memset(namebuf, '[', dim);
+
+ utf* u = utf_new(namebuf, namelen);
+
+ MFREE(namebuf, char, namelen);
+
+ c = get_array_class(u,
+ element->classloader,
+ element->classloader,
+ link);
+
+ return c;
+ }
+
+
+ /* class_lookup_classref *******************************************************
+
+ Looks up the constant_classref for a given classname in the classref
+ tables of a class.
+
+ IN:
+ cls..............the class containing the reference
+ name.............the name of the class refered to
+
+ RETURN VALUE:
+ a pointer to a constant_classref, or
+ NULL if the reference was not found
+
+ *******************************************************************************/
+
+ constant_classref *class_lookup_classref(classinfo *cls, utf *name)
+ {
+ constant_classref *ref;
+ extra_classref *xref;
+ int count;
+
+ assert(cls);
+ assert(name);
+ assert(!cls->classrefcount || cls->classrefs);
+
+ /* first search the main classref table */
+ count = cls->classrefcount;
+ ref = cls->classrefs;
+ for (; count; --count, ++ref)
+ if (ref->name == name)
+ return ref;
+
+ /* next try the list of extra classrefs */
+ for (xref = cls->extclassrefs; xref; xref = xref->next) {
+ if (xref->classref.name == name)
+ return &(xref->classref);
+ }
+
+ /* not found */
+ return NULL;
+ }
+
+
+ /* class_get_classref **********************************************************
+
+ Returns the constant_classref for a given classname.
+
+ IN:
+ cls..............the class containing the reference
+ name.............the name of the class refered to
+
+ RETURN VALUE:
+ a pointer to a constant_classref (never NULL)
+
+ NOTE:
+ The given name is not checked for validity!
+
+ *******************************************************************************/
+
+ constant_classref *class_get_classref(classinfo *cls, utf *name)
+ {
+ constant_classref *ref;
+ extra_classref *xref;
+
+ assert(cls);
+ assert(name);
+
+ ref = class_lookup_classref(cls,name);
+ if (ref)
+ return ref;
+
+ xref = NEW(extra_classref);
+ CLASSREF_INIT(xref->classref,cls,name);
+
+ xref->next = cls->extclassrefs;
+ cls->extclassrefs = xref;
+
+ return &(xref->classref);
+ }
+
+
+ /* class_get_self_classref *****************************************************
+
+ Returns the constant_classref to the class itself.
+
+ IN:
+ cls..............the class containing the reference
+
+ RETURN VALUE:
+ a pointer to a constant_classref (never NULL)
+
+ *******************************************************************************/
+
+ constant_classref *class_get_self_classref(classinfo *cls)
+ {
+ /* XXX this should be done in a faster way. Maybe always make */
+ /* the classref of index 0 a self reference. */
+ return class_get_classref(cls,cls->name);
+ }
+
+ /* class_get_classref_multiarray_of ********************************************
+
+ Returns an array type reference with the given dimension and element class
+ reference.
+
+ IN:
+ dim..............the requested dimension
+ dim must be in [1;255]. This is NOT checked!
+ ref..............the component class reference
+
+ RETURN VALUE:
+ a pointer to the class reference for the array type
+
+ NOTE:
+ The referer of `ref` is used as the referer for the new classref.
+
+ *******************************************************************************/
+
+ constant_classref *class_get_classref_multiarray_of(s4 dim, constant_classref *ref)
+ {
+ s4 namelen;
+ char *namebuf;
+ constant_classref *cr;
+
+ assert(ref);
+ assert(dim >= 1 && dim <= 255);
+
+ /* Assemble the array class name */
+ namelen = ref->name->blength;
+
+ if (ref->name->text[0] == '[') {
+ /* the element is itself an array */
+ namebuf = MNEW(char, namelen + dim);
+ memcpy(namebuf + dim, ref->name->text, namelen);
+ namelen += dim;
+ }
+ else {
+ /* the element is a non-array class */
+ namebuf = MNEW(char, namelen + 2 + dim);
+ namebuf[dim] = 'L';
+ memcpy(namebuf + dim + 1, ref->name->text, namelen);
+ namelen += (2 + dim);
+ namebuf[namelen - 1] = ';';
+ }
+ memset(namebuf, '[', dim);
+
+ utf* u = utf_new(namebuf, namelen);
+
+ MFREE(namebuf, char, namelen);
+
+ cr = class_get_classref(ref->referer, u);
+
+ return cr;
+ }
+
+
+ /* class_get_classref_component_of *********************************************
+
+ Returns the component classref of a given array type reference
+
+ IN:
+ ref..............the array type reference
+
+ RETURN VALUE:
+ a reference to the component class, or
+ NULL if `ref` is not an object array type reference
+
+ NOTE:
+ The referer of `ref` is used as the referer for the new classref.
+
+ *******************************************************************************/
+
+ constant_classref *class_get_classref_component_of(constant_classref *ref)
+ {
+ s4 namelen;
+ char *name;
+
+ assert(ref);
+
+ name = ref->name->text;
+ if (*name++ != '[')
+ return NULL;
+
+ namelen = ref->name->blength - 1;
+ if (*name == 'L') {
+ name++;
+ namelen -= 2;
+ }
+ else if (*name != '[') {
+ return NULL;
+ }
+
+ return class_get_classref(ref->referer, utf_new(name, namelen));
+ }
+
+
+ /* class_findmethod ************************************************************
+
+ Searches a 'classinfo' structure for a method having the given name
+ and descriptor. If descriptor is NULL, it is ignored.
+
+ *******************************************************************************/
+
+ methodinfo *class_findmethod(classinfo *c, utf *name, utf *desc)
+ {
+ methodinfo *m;
+ s4 i;
+
+ for (i = 0; i < c->methodscount; i++) {
+ m = &(c->methods[i]);
+
+ if ((m->name == name) && ((desc == NULL) || (m->descriptor == desc)))
+ return m;
+ }
+
+ return NULL;
+ }
+
+
+ /* class_resolvemethod *********************************************************
+
+ Searches a class and it's super classes for a method.
+
+ Superinterfaces are *not* searched.
+
+ *******************************************************************************/
+
+ methodinfo *class_resolvemethod(classinfo *c, utf *name, utf *desc)
+ {
+ methodinfo *m;
+
+ while (c) {
+ m = class_findmethod(c, name, desc);
+
+ if (m)
+ return m;
+
+ /* JVM Specification bug:
+
+ It is important NOT to resolve special <init> and <clinit>
+ methods to super classes or interfaces; yet, this is not
+ explicited in the specification. Section 5.4.3.3 should be
+ updated appropriately. */
+
+ if (name == utf_init || name == utf_clinit)
+ return NULL;
+
+ c = c->super;
+ }
+
+ return NULL;
+ }
+
+
+ /* class_resolveinterfacemethod_intern *****************************************
+
+ Internally used helper function. Do not use this directly.
+
+ *******************************************************************************/
+
+ static methodinfo *class_resolveinterfacemethod_intern(classinfo *c,
+ utf *name, utf *desc)
+ {
+ methodinfo *m;
+ s4 i;
+
+ /* try to find the method in the class */
+
+ m = class_findmethod(c, name, desc);
+
+ if (m != NULL)
+ return m;
+
+ /* No method found? Try the super interfaces. */
+
+ for (i = 0; i < c->interfacescount; i++) {
+ m = class_resolveinterfacemethod_intern(c->interfaces[i], name, desc);
+
+ if (m != NULL)
+ return m;
+ }
+
+ /* no method found */
+
+ return NULL;
+ }
+
+
+ /* class_resolveclassmethod ****************************************************
+
+ Resolves a reference from REFERER to a method with NAME and DESC in
+ class C.
+
+ If the method cannot be resolved the return value is NULL. If
+ EXCEPT is true *exceptionptr is set, too.
+
+ *******************************************************************************/
+
+ methodinfo *class_resolveclassmethod(classinfo *c, utf *name, utf *desc,
+ classinfo *referer, bool throwexception)
+ {
+ classinfo *cls;
+ methodinfo *m;
+ s4 i;
+
+ /* if (c->flags & ACC_INTERFACE) { */
+ /* if (throwexception) */
+ /* *exceptionptr = */
+ /* new_exception(string_java_lang_IncompatibleClassChangeError); */
+ /* return NULL; */
+ /* } */
+
+ /* try class c and its superclasses */
+
+ cls = c;
+
+ m = class_resolvemethod(cls, name, desc);
+
+ if (m != NULL)
+ goto found;
+
+ /* Try the super interfaces. */
+
+ for (i = 0; i < c->interfacescount; i++) {
+ m = class_resolveinterfacemethod_intern(c->interfaces[i], name, desc);
+
+ if (m != NULL)
+ goto found;
+ }
+
+ if (throwexception)
+ exceptions_throw_nosuchmethoderror(c, name, desc);
+
+ return NULL;
+
+ found:
+ if ((m->flags & ACC_ABSTRACT) && !(c->flags & ACC_ABSTRACT)) {
+ if (throwexception)
+ exceptions_throw_abstractmethoderror();
+
+ return NULL;
+ }
+
+ /* XXX check access rights */
+
+ return m;
+ }
+
+
+ /* class_resolveinterfacemethod ************************************************
+
+ Resolves a reference from REFERER to a method with NAME and DESC in
+ interface C.
+
+ If the method cannot be resolved the return value is NULL. If
+ EXCEPT is true *exceptionptr is set, too.
+
+ *******************************************************************************/
+
+ methodinfo *class_resolveinterfacemethod(classinfo *c, utf *name, utf *desc,
+ classinfo *referer, bool throwexception)
+ {
+ methodinfo *mi;
+
+ if (!(c->flags & ACC_INTERFACE)) {
+ if (throwexception)
+ exceptions_throw_incompatibleclasschangeerror(c, "Not an interface");
+
+ return NULL;
+ }
+
+ mi = class_resolveinterfacemethod_intern(c, name, desc);
+
+ if (mi != NULL)
+ return mi;
+
+ /* try class java.lang.Object */
+
+ mi = class_findmethod(class_java_lang_Object, name, desc);
+
+ if (mi != NULL)
+ return mi;
+
+ if (throwexception)
+ exceptions_throw_nosuchmethoderror(c, name, desc);
+
+ return NULL;
+ }
+
+
+ /* class_findfield *************************************************************
+
+ Searches for field with specified name and type in a classinfo
+ structure. If no such field is found NULL is returned.
+
+ *******************************************************************************/
+
+ fieldinfo *class_findfield(classinfo *c, utf *name, utf *desc)
+ {
+ s4 i;
+
+ for (i = 0; i < c->fieldscount; i++)
+ if ((c->fields[i].name == name) && (c->fields[i].descriptor == desc))
+ return &(c->fields[i]);
+
+ if (c->super != NULL)
+ return class_findfield(c->super, name, desc);
+
+ return NULL;
+ }
+
+
+ /* class_findfield_approx ******************************************************
+
+ Searches in 'classinfo'-structure for a field with the specified
+ name.
+
+ *******************************************************************************/
+
+ fieldinfo *class_findfield_by_name(classinfo* c, utf* name)
+ {
+ for (int32_t i = 0; i < c->fieldscount; i++) {
+ fieldinfo* f = &(c->fields[i]);
+
+ if (f->name == name)
+ return f;
+ }
+
+ // Field not found.
+ exceptions_throw_nosuchfielderror(c, name);
+ return NULL;
+ }
+
+
+ /****************** Function: class_resolvefield_int ***************************
+
+ This is an internally used helper function. Do not use this directly.
+
+ Tries to resolve a field having the given name and type.
+ If the field cannot be resolved, NULL is returned.
+
+ *******************************************************************************/
+
+ static fieldinfo *class_resolvefield_int(classinfo *c, utf *name, utf *desc)
+ {
+ fieldinfo *fi;
+ s4 i;
+
+ /* search for field in class c */
+
+ for (i = 0; i < c->fieldscount; i++) {
+ if ((c->fields[i].name == name) && (c->fields[i].descriptor == desc)) {
+ return &(c->fields[i]);
+ }
+ }
+
+ /* Try super interfaces recursively. */
+
+ for (i = 0; i < c->interfacescount; i++) {
+ fi = class_resolvefield_int(c->interfaces[i], name, desc);
+
+ if (fi != NULL)
+ return fi;
+ }
+
+ /* Try super class. */
+
+ if (c->super != NULL)
+ return class_resolvefield_int(c->super, name, desc);
+
+ /* not found */
+
+ return NULL;
+ }
+
+
+ /********************* Function: class_resolvefield ***************************
+
+ Resolves a reference from REFERER to a field with NAME and DESC in class C.
+
+ If the field cannot be resolved, an exception is thrown and the
+ return value is NULL.
+
+ *******************************************************************************/
+
+ fieldinfo *class_resolvefield(classinfo *c, utf *name, utf *desc, classinfo *referer)
+ {
+ fieldinfo *fi;
+
+ fi = class_resolvefield_int(c, name, desc);
+
+ if (!fi) {
+ exceptions_throw_nosuchfielderror(c, name);
+ return NULL;
+ }
+
+ /* XXX check access rights */
+
+ return fi;
+ }
+
+
+ /* class_issubclass ************************************************************
+
+ Checks if sub is a descendant of super.
+
+ *******************************************************************************/
+
+ bool class_issubclass(classinfo *sub, classinfo *super)
+ {
+ classinfo *c;
+
+ c = sub;
+
+ for (;;) {
+ /* We reached java/lang/Object and did not find the requested
+ super class. */
+
+ if (c == NULL)
+ return false;
+
+ /* We found the requested super class. */
+
+ if (c == super)
+ return true;
+
+ c = c->super;
+ }
+ }
+
+
+ /* class_isanysubclass *********************************************************
+
+ Checks a subclass relation between two classes. Implemented
+ interfaces are interpreted as super classes.
+
+ Return value: 1 ... sub is subclass of super
+ 0 ... otherwise
+
+ *******************************************************************************/
+
+ bool class_isanysubclass(classinfo *sub, classinfo *super)
+ {
+ uint32_t diffval;
+ bool result;
+
+ /* This is the trivial case. */
+
+ if (sub == super)
+ return true;
+
+ /* Primitive classes are only subclasses of themselves. */
+
+ if (class_is_primitive(sub) || class_is_primitive(super))
+ return false;
+
+ /* Check for interfaces. */
+
+ if (super->flags & ACC_INTERFACE) {
+ result = (sub->vftbl->interfacetablelength > super->index) &&
+ (sub->vftbl->interfacetable[-super->index] != NULL);
+ }
+ else {
+ /* java.lang.Object is the only super class of any
+ interface. */
+
+ if (sub->flags & ACC_INTERFACE)
+ return (super == class_java_lang_Object);
+
+ linker_classrenumber_mutex->lock();
+
+ diffval = sub->vftbl->baseval - super->vftbl->baseval;
+ result = diffval <= (uint32_t) super->vftbl->diffval;
+
+ linker_classrenumber_mutex->unlock();
+ }
+
+ return result;
+ }
+
+
+ /* class_is_assignable_from ****************************************************
+
+ Return whether an instance of the "from" class parameter would be
+ an instance of this class "to" as well.
+
+ ARGUMENTS:
+ to ..... class
+ from ... class
+
+ RETURN:
+ true .... is assignable
+ false ... is not assignable
+
+ *******************************************************************************/
+
+ bool class_is_assignable_from(classinfo *to, classinfo *from)
+ {
+ if (!(to->state & CLASS_LINKED))
+ if (!link_class(to))
+ return false;
+
+ if (!(from->state & CLASS_LINKED))
+ if (!link_class(from))
+ return false;
+
+ return class_isanysubclass(from, to);
+ }
+
+
+ /* class_is_instance ***********************************************************
+
+ Return if the given Java object is an instance of the given class.
+
+ ARGUMENTS:
+ c ... class
+ h ... Java object
+
+ RETURN:
+ true .... is instance
+ false ... is not instance
+
+ *******************************************************************************/
+
+ bool class_is_instance(classinfo *c, java_handle_t *h)
+ {
+ if (!(c->state & CLASS_LINKED))
+ if (!link_class(c))
+ return false;
+
+ return builtin_instanceof(h, c);
+ }
+
+
+ /* class_get_componenttype *****************************************************
+
+ Return the component class of the given class. If the given class
+ is not an array, return NULL.
+
+ *******************************************************************************/
+
+ classinfo *class_get_componenttype(classinfo *c)
+ {
+ classinfo *component;
+ arraydescriptor *ad;
+
+ /* XXX maybe we could find a way to do this without linking. */
+ /* This way should be safe and easy, however. */
+
+ if (!(c->state & CLASS_LINKED))
+ if (!link_class(c))
+ return NULL;
+
+ ad = c->vftbl->arraydesc;
+
+ if (ad == NULL)
+ return NULL;
+
+ if (ad->arraytype == ARRAYTYPE_OBJECT)
+ component = ad->componentvftbl->clazz;
+ else
+ component = Primitive::get_class_by_type(ad->arraytype);
+
+ return component;
+ }
+
+
+ /* class_get_declaredclasses ***************************************************
+
+ Return an array of declared classes of the given class.
+
+ *******************************************************************************/
+
+ java_handle_objectarray_t *class_get_declaredclasses(classinfo *c, bool publicOnly)
+ {
+ classref_or_classinfo inner;
+ classref_or_classinfo outer;
+ utf *outername;
+ int declaredclasscount; /* number of declared classes */
+ int pos; /* current declared class */
+ java_handle_objectarray_t *oa; /* array of declared classes */
+ int i;
+ classinfo *ic;
+
+ declaredclasscount = 0;
+
+ if (!class_is_primitive(c) && !class_is_array(c)) {
+ /* Determine number of declared classes. */
+
+ for (i = 0; i < c->innerclasscount; i++) {
+ /* Get outer-class. If the inner-class is not a member
+ class, the outer-class is NULL. */
+
+ outer = c->innerclass[i].outer_class;
+
+ if (outer.any == NULL)
+ continue;
+
+ /* Check if outer-class is a classref or a real class and
+ get the class name from the structure. */
+
+ outername = IS_CLASSREF(outer) ? outer.ref->name : outer.cls->name;
+
+ /* Outer class is this class. */
+
+ if ((outername == c->name) &&
+ ((publicOnly == 0) || (c->innerclass[i].flags & ACC_PUBLIC)))
+ declaredclasscount++;
+ }
+ }
+
+ /* Allocate Class[] and check for OOM. */
+
+ oa = builtin_anewarray(declaredclasscount, class_java_lang_Class);
+
+ if (oa == NULL)
+ return NULL;
+
+ for (i = 0, pos = 0; i < c->innerclasscount; i++) {
+ inner = c->innerclass[i].inner_class;
+ outer = c->innerclass[i].outer_class;
+
+ /* Get outer-class. If the inner-class is not a member class,
+ the outer-class is NULL. */
+
+ if (outer.any == NULL)
+ continue;
+
+ /* Check if outer_class is a classref or a real class and get
+ the class name from the structure. */
+
+ outername = IS_CLASSREF(outer) ? outer.ref->name : outer.cls->name;
+
+ /* Outer class is this class. */
+
+ if ((outername == c->name) &&
+ ((publicOnly == 0) || (c->innerclass[i].flags & ACC_PUBLIC))) {
+
+ ic = resolve_classref_or_classinfo_eager(inner, false);
+
+ if (ic == NULL)
+ return NULL;
+
+ if (!(ic->state & CLASS_LINKED))
+ if (!link_class(ic))
+ return NULL;
+
+ LLNI_array_direct(oa, pos++) = (java_object_t *) ic;
+ }
+ }
+
+ return oa;
+ }
+
+
+ /**
+ * Return an array of declared constructors of the given class.
+ *
+ * @param c class to get the constructors of
+ * @param publicOnly show only public fields
+ *
+ * @return array of java.lang.reflect.Constructor
+ */
+ #if defined(ENABLE_JAVASE)
+ java_handle_objectarray_t *class_get_declaredconstructors(classinfo *c, bool publicOnly)
+ {
+ methodinfo* m;
+ java_handle_objectarray_t* oa;
+ int count;
+ int index;
+ int i;
+
+ /* Determine number of constructors. */
+
+ count = 0;
+
+ for (i = 0; i < c->methodscount; i++) {
+ m = &(c->methods[i]);
+
+ if (((m->flags & ACC_PUBLIC) || (publicOnly == 0)) &&
+ (m->name == utf_init))
+ count++;
+ }
+
+ /* Create array of constructors. */
+
+ oa = builtin_anewarray(count, class_java_lang_reflect_Constructor);
+
+ if (oa == NULL)
+ return NULL;
+
+ /* Get the constructors and store them in the array. */
+
+ for (i = 0, index = 0; i < c->methodscount; i++) {
+ m = &(c->methods[i]);
+
+ if (((m->flags & ACC_PUBLIC) || (publicOnly == 0)) &&
+ (m->name == utf_init)) {
+ // Create a java.lang.reflect.Constructor object.
+
+ java_lang_reflect_Constructor rc(m);
+
+ /* Store object into array. */
+
+ array_objectarray_element_set(oa, index, rc.get_handle());
+ index++;
+ }
+ }
+
+ return oa;
+ }
+ #endif
+
+
+ /* class_get_declaredfields ****************************************************
+
+ Return an array of declared fields of the given class.
+
+ ARGUMENTS:
+ c ............ class to get the fields of
+ publicOnly ... show only public fields
+
+ RETURN:
+ array of java.lang.reflect.Field
+
+ *******************************************************************************/
+
+ #if defined(ENABLE_JAVASE)
+ java_handle_objectarray_t *class_get_declaredfields(classinfo *c, bool publicOnly)
+ {
+ java_handle_objectarray_t *oa;
+ fieldinfo *f;
+ int count;
+ int index;
+ int i;
+
+ /* Determine number of fields. */
+
+ count = 0;
+
+ for (i = 0; i < c->fieldscount; i++)
+ if ((c->fields[i].flags & ACC_PUBLIC) || (publicOnly == 0))
+ count++;
+
+ /* Create array of fields. */
+
+ oa = builtin_anewarray(count, class_java_lang_reflect_Field);
+
+ if (oa == NULL)
+ return NULL;
+
+ /* Get the fields and store them in the array. */
+
+ for (i = 0, index = 0; i < c->fieldscount; i++) {
+ f = &(c->fields[i]);
+
+ if ((f->flags & ACC_PUBLIC) || (publicOnly == 0)) {
+ // Create a java.lang.reflect.Field object.
+
+ java_lang_reflect_Field rf(f);
+
+ /* Store object into array. */
+
+ array_objectarray_element_set(oa, index, rf.get_handle());
+ index++;
+ }
+ }
+
+ return oa;
+ }
+ #endif
+
+
+ /* class_get_declaredmethods ***************************************************
+
+ Return an array of declared methods of the given class.
+
+ ARGUMENTS:
+ c ............ class to get the methods of
+ publicOnly ... show only public methods
+
+ RETURN:
+ array of java.lang.reflect.Method
+
+ *******************************************************************************/
+
+ #if defined(ENABLE_JAVASE)
+ java_handle_objectarray_t *class_get_declaredmethods(classinfo *c, bool publicOnly)
+ {
+ java_handle_objectarray_t *oa; /* result: array of Method-objects */
+ methodinfo *m; /* the current method to be represented */
+ int count;
+ int index;
+ int i;
+
+ /* JOWENN: array classes do not declare methods according to mauve
+ test. It should be considered, if we should return to my old
+ clone method overriding instead of declaring it as a member
+ function. */
+
+ if (class_is_array(c))
+ return builtin_anewarray(0, class_java_lang_reflect_Method);
+
+ /* Determine number of methods. */
+
+ count = 0;
+
+ for (i = 0; i < c->methodscount; i++) {
+ m = &(c->methods[i]);
+
+ if (((m->flags & ACC_PUBLIC) || (publicOnly == false)) &&
+ ((m->name != utf_init) && (m->name != utf_clinit)) &&
+ !(m->flags & ACC_MIRANDA))
+ count++;
+ }
+
+ /* Create array of methods. */
+
+ oa = builtin_anewarray(count, class_java_lang_reflect_Method);
+
+ if (oa == NULL)
+ return NULL;
+
+ /* Get the methods and store them in the array. */
+
+ for (i = 0, index = 0; i < c->methodscount; i++) {
+ m = &(c->methods[i]);
+
+ if (((m->flags & ACC_PUBLIC) || (publicOnly == false)) &&
+ ((m->name != utf_init) && (m->name != utf_clinit)) &&
+ !(m->flags & ACC_MIRANDA)) {
+ // Create java.lang.reflect.Method object.
+
+ java_lang_reflect_Method rm(m);
+
+ /* Store object into array. */
+
+ array_objectarray_element_set(oa, index, rm.get_handle());
+ index++;
+ }
+ }
+
+ return oa;
+ }
+ #endif
+
+
+ /* class_get_declaringclass ****************************************************
+
+ If the class or interface given is a member of another class,
+ return the declaring class. For array and primitive classes return
+ NULL.
+
+ *******************************************************************************/
+
+ classinfo *class_get_declaringclass(classinfo *c)
+ {
+ classref_or_classinfo cr;
+ classinfo *dc;
+
+ /* Get declaring class. */
+
+ cr = c->declaringclass;
+
+ if (cr.any == NULL)
+ return NULL;
+
+ /* Resolve the class if necessary. */
+
+ if (IS_CLASSREF(cr)) {
+ /* dc = resolve_classref_eager(cr.ref); */
+ dc = resolve_classref_or_classinfo_eager(cr, true);
+
+ if (dc == NULL)
+ return NULL;
+
+ /* Store the resolved class in the class structure. */
+
+ cr.cls = dc;
+ }
+
+ dc = cr.cls;
+
+ return dc;
+ }
+
+
+ /* class_get_enclosingclass ****************************************************
+
+ Return the enclosing class for the given class.
+
+ *******************************************************************************/
+
+ classinfo *class_get_enclosingclass(classinfo *c)
+ {
+ classref_or_classinfo cr;
+ classinfo *ec;
+
+ /* Get enclosing class. */
+
+ cr = c->enclosingclass;
+
+ if (cr.any == NULL)
+ return NULL;
+
+ /* Resolve the class if necessary. */
+
+ if (IS_CLASSREF(cr)) {
+ /* ec = resolve_classref_eager(cr.ref); */
+ ec = resolve_classref_or_classinfo_eager(cr, true);
+
+ if (ec == NULL)
+ return NULL;
+
+ /* Store the resolved class in the class structure. */
+
+ cr.cls = ec;
+ }
+
+ ec = cr.cls;
+
+ return ec;
+ }
+
+
+ /**
+ * Return the enclosing constructor as java.lang.reflect.Constructor
+ * object for the given class.
+ *
+ * @param c class to return the enclosing constructor for
+ *
+ * @return java.lang.reflect.Constructor object of the enclosing
+ * constructor
+ */
+ #if defined(ENABLE_JAVASE)
+ java_handle_t* class_get_enclosingconstructor(classinfo *c)
+ {
+ methodinfo* m;
+
+ m = class_get_enclosingmethod_raw(c);
+
+ if (m == NULL)
+ return NULL;
+
+ /* Check for <init>. */
+
+ if (m->name != utf_init)
+ return NULL;
+
+ // Create a java.lang.reflect.Constructor object.
+
+ java_lang_reflect_Constructor rc(m);
+
+ return rc.get_handle();
+ }
+ #endif
+
+
+ /* class_get_enclosingmethod ***************************************************
+
+ Return the enclosing method for the given class.
+
+ IN:
+ c ... class to return the enclosing method for
+
+ RETURN:
+ methodinfo of the enclosing method
+
+ *******************************************************************************/
+
+ methodinfo *class_get_enclosingmethod_raw(classinfo *c)
+ {
+ constant_nameandtype *cn;
+ classinfo *ec;
+ methodinfo *m;
+
+ /* get enclosing class and method */
+
+ ec = class_get_enclosingclass(c);
+ cn = c->enclosingmethod;
+
+ /* check for enclosing class and method */
+
+ if (ec == NULL)
+ return NULL;
+
+ if (cn == NULL)
+ return NULL;
+
+ /* find method in enclosing class */
+
+ m = class_findmethod(ec, cn->name, cn->descriptor);
+
+ if (m == NULL) {
+ exceptions_throw_internalerror("Enclosing method doesn't exist");
+ return NULL;
+ }
+
+ return m;
+ }
+
+
+ /**
+ * Return the enclosing method as java.lang.reflect.Method object for
+ * the given class.
+ *
+ * @param c class to return the enclosing method for
+ *
+ * @return java.lang.reflect.Method object of the enclosing method
+ */
+ #if defined(ENABLE_JAVASE)
+ java_handle_t* class_get_enclosingmethod(classinfo *c)
+ {
+ methodinfo* m;
+
+ m = class_get_enclosingmethod_raw(c);
+
+ if (m == NULL)
+ return NULL;
+
+ /* check for <init> */
+
+ if (m->name == utf_init)
+ return NULL;
+
+ // Create a java.lang.reflect.Method object.
+
+ java_lang_reflect_Method rm(m);
+
+ return rm.get_handle();
+ }
+ #endif
+
+
+ /* class_get_interfaces ********************************************************
+
+ Return an array of interfaces of the given class.
+
+ *******************************************************************************/
+
+ java_handle_objectarray_t *class_get_interfaces(classinfo *c)
+ {
+ classinfo *ic;
+ java_handle_objectarray_t *oa;
+ u4 i;
+
+ if (!(c->state & CLASS_LINKED))
+ if (!link_class(c))
+ return NULL;
+
+ oa = builtin_anewarray(c->interfacescount, class_java_lang_Class);
+
+ if (oa == NULL)
+ return NULL;
+
+ for (i = 0; i < c->interfacescount; i++) {
+ ic = c->interfaces[i];
+
+ LLNI_array_direct(oa, i) = (java_object_t *) ic;
+ }
+
+ return oa;
+ }
+
+
+ /* class_get_annotations *******************************************************
+
+ Get the unparsed declared annotations in a byte array
+ of the given class.
+
+ IN:
+ c........the class of which the annotations should be returned
+
+ RETURN VALUE:
+ The unparsed declared annotations in a byte array
+ (or NULL if there aren't any).
+
+ *******************************************************************************/
+
+ java_handle_bytearray_t *class_get_annotations(classinfo *c)
+ {
+ #if defined(ENABLE_ANNOTATIONS)
+ java_handle_t *annotations; /* unparsed annotations */
+
+ LLNI_classinfo_field_get(c, annotations, annotations);
+
+ return (java_handle_bytearray_t*)annotations;
+ #else
+ return NULL;
+ #endif
+ }
+
+
+ /* class_get_modifiers *********************************************************
+
+ Get the modifier flags of the given class.
+
+ IN:
+ c....the class of which the modifier flags should be returned
+ ignoreInnerClassesAttrib
+ RETURN VALUE:
+ modifier flags
+
+ *******************************************************************************/
+
+ int32_t class_get_modifiers(classinfo *c, bool ignoreInnerClassesAttrib)
+ {
+ classref_or_classinfo inner;
+ classref_or_classinfo outer;
+ utf *innername;
+ int i;
+
+ if (!ignoreInnerClassesAttrib && (c->innerclasscount != 0)) {
+ /* search for passed class as inner class */
+
+ for (i = 0; i < c->innerclasscount; i++) {
+ inner = c->innerclass[i].inner_class;
+ outer = c->innerclass[i].outer_class;
+
+ /* Check if inner is a classref or a real class and get
+ the name of the structure */
+
+ innername = IS_CLASSREF(inner) ? inner.ref->name : inner.cls->name;
+
+ /* innerclass is this class */
+
+ if (innername == c->name) {
+ /* has the class actually an outer class? */
+
+ if (outer.any)
+ /* return flags got from the outer class file */
+ return c->innerclass[i].flags & ACC_CLASS_REFLECT_MASK;
+ else
+ return c->flags & ACC_CLASS_REFLECT_MASK;
+ }
+ }
+ }
+
+ /* passed class is no inner class or it was not requested */
+
+ return c->flags & ACC_CLASS_REFLECT_MASK;
+ }
+
+
+ /* class_get_signature *********************************************************
+
+ Return the signature of the given class. For array and primitive
+ classes return NULL.
+
+ *******************************************************************************/
+
+ #if defined(ENABLE_JAVASE)
+ utf *class_get_signature(classinfo *c)
+ {
+ /* For array and primitive classes return NULL. */
+
+ if (class_is_array(c) || class_is_primitive(c))
+ return NULL;
+
+ return c->signature;
+ }
+ #endif
+
+
+ /* class_printflags ************************************************************
+
+ Prints flags of a class.
+
+ *******************************************************************************/
+
+ #if !defined(NDEBUG)
+ void class_printflags(classinfo *c)
+ {
+ if (c == NULL) {
+ printf("NULL");
+ return;
+ }
+
+ if (c->flags & ACC_PUBLIC) printf(" PUBLIC");
+ if (c->flags & ACC_PRIVATE) printf(" PRIVATE");
+ if (c->flags & ACC_PROTECTED) printf(" PROTECTED");
+ if (c->flags & ACC_STATIC) printf(" STATIC");
+ if (c->flags & ACC_FINAL) printf(" FINAL");
+ if (c->flags & ACC_SYNCHRONIZED) printf(" SYNCHRONIZED");
+ if (c->flags & ACC_VOLATILE) printf(" VOLATILE");
+ if (c->flags & ACC_TRANSIENT) printf(" TRANSIENT");
+ if (c->flags & ACC_NATIVE) printf(" NATIVE");
+ if (c->flags & ACC_INTERFACE) printf(" INTERFACE");
+ if (c->flags & ACC_ABSTRACT) printf(" ABSTRACT");
+ }
+ #endif
+
+
+ /* class_print *****************************************************************
+
+ Prints classname plus flags.
+
+ *******************************************************************************/
+
+ #if !defined(NDEBUG)
+ void class_print(classinfo *c)
+ {
+ if (c == NULL) {
+ printf("NULL");
+ return;
+ }
+
+ utf_display_printable_ascii(c->name);
+ class_printflags(c);
+ }
+ #endif
+
+
+ /* class_classref_print ********************************************************
+
+ Prints classname plus referer class.
+
+ *******************************************************************************/
+
+ #if !defined(NDEBUG)
+ void class_classref_print(constant_classref *cr)
+ {
+ if (cr == NULL) {
+ printf("NULL");
+ return;
+ }
+
+ utf_display_printable_ascii(cr->name);
+ printf("(ref.by ");
+ if (cr->referer)
+ class_print(cr->referer);
+ else
+ printf("NULL");
+ printf(")");
+ }
+ #endif
+
+
+ /* class_println ***************************************************************
+
+ Prints classname plus flags and new line.
+
+ *******************************************************************************/
+
+ #if !defined(NDEBUG)
+ void class_println(classinfo *c)
+ {
+ class_print(c);
+ printf("\n");
+ }
+ #endif
+
+
+ /* class_classref_println ******************************************************
+
+ Prints classname plus referer class and new line.
+
+ *******************************************************************************/
+
+ #if !defined(NDEBUG)
+ void class_classref_println(constant_classref *cr)
+ {
+ class_classref_print(cr);
+ printf("\n");
+ }
+ #endif
+
+
+ /* class_classref_or_classinfo_print *******************************************
+
+ Prints classname plus referer class.
+
+ *******************************************************************************/
+
+ #if !defined(NDEBUG)
+ void class_classref_or_classinfo_print(classref_or_classinfo c)
+ {
+ if (c.any == NULL) {
+ printf("(classref_or_classinfo) NULL");
+ return;
+ }
+ if (IS_CLASSREF(c))
+ class_classref_print(c.ref);
+ else
+ class_print(c.cls);
+ }
+ #endif
+
+
+ /* class_classref_or_classinfo_println *****************************************
+
+ Prints classname plus referer class and a newline.
+
+ *******************************************************************************/
+
+ #if !defined(NDEBUG)
+ void class_classref_or_classinfo_println(classref_or_classinfo c)
+ {
+ class_classref_or_classinfo_print(c);
+ printf("\n");
+ }
+ #endif
+
+
+ /* class_showconstantpool ******************************************************
+
+ Dump the constant pool of the given class to stdout.
+
+ *******************************************************************************/
+
+ #if !defined(NDEBUG)
+ void class_showconstantpool (classinfo *c)
+ {
+ u4 i;
+ void* e;
+
+ printf ("---- dump of constant pool ----\n");
+
+ for (i=0; i<c->cpcount; i++) {
+ printf ("#%d: ", (int) i);
+
+ e = c -> cpinfos [i];
+ if (e) {
+
+ switch (c -> cptags [i]) {
+ case CONSTANT_Class:
+ printf ("Classreference -> ");
+ utf_display_printable_ascii ( ((constant_classref*)e) -> name );
+ break;
+ case CONSTANT_Fieldref:
+ printf ("Fieldref -> ");
+ field_fieldref_print((constant_FMIref *) e);
+ break;
+ case CONSTANT_Methodref:
+ printf ("Methodref -> ");
+ method_methodref_print((constant_FMIref *) e);
+ break;
+ case CONSTANT_InterfaceMethodref:
+ printf ("InterfaceMethod -> ");
+ method_methodref_print((constant_FMIref *) e);
+ break;
+ case CONSTANT_String:
+ printf ("String -> ");
+ utf_display_printable_ascii ((utf*) e);
+ break;
+ case CONSTANT_Integer:
+ printf ("Integer -> %d", (int) ( ((constant_integer*)e) -> value) );
+ break;
+ case CONSTANT_Float:
+ printf ("Float -> %f", ((constant_float*)e) -> value);
+ break;
+ case CONSTANT_Double:
+ printf ("Double -> %f", ((constant_double*)e) -> value);
+ break;
+ case CONSTANT_Long:
+ printf ("Long -> %ld", (long int) ((constant_long*)e) -> value);
+ break;
+ case CONSTANT_NameAndType:
+ {
+ constant_nameandtype *cnt = (constant_nameandtype *) e;
+ printf ("NameAndType: ");
+ utf_display_printable_ascii (cnt->name);
+ printf (" ");
+ utf_display_printable_ascii (cnt->descriptor);
+ }
+ break;
+ case CONSTANT_Utf8:
+ printf ("Utf8 -> ");
+ utf_display_printable_ascii ((utf*) e);
+ break;
+ default:
+ log_text("Invalid type of ConstantPool-Entry");
+ assert(0);
+ }
+ }
+
+ printf ("\n");
+ }
+ }
+ #endif /* !defined(NDEBUG) */
+
+
+ /* class_showmethods ***********************************************************
+
+ Dump info about the fields and methods of the given class to stdout.
+
+ *******************************************************************************/
+
+ #if !defined(NDEBUG)
+ void class_showmethods (classinfo *c)
+ {
+ s4 i;
+
+ printf("--------- Fields and Methods ----------------\n");
+ printf("Flags: ");
+ class_printflags(c);
+ printf("\n");
+
+ printf("This: ");
+ utf_display_printable_ascii(c->name);
+ printf("\n");
+
+ if (c->super) {
+ printf("Super: ");
+ utf_display_printable_ascii(c->super->name);
+ printf ("\n");
+ }
+
+ printf("Index: %d\n", c->index);
+
+ printf("Interfaces:\n");
+ for (i = 0; i < c->interfacescount; i++) {
+ printf(" ");
+ utf_display_printable_ascii(c->interfaces[i]->name);
+ printf (" (%d)\n", c->interfaces[i]->index);
+ }
+
+ printf("Fields:\n");
+ for (i = 0; i < c->fieldscount; i++)
+ field_println(&(c->fields[i]));
+
+ printf("Methods:\n");
+ for (i = 0; i < c->methodscount; i++) {
+ methodinfo *m = &(c->methods[i]);
+
+ if (!(m->flags & ACC_STATIC))
+ printf("vftblindex: %d ", m->vftblindex);
+
+ method_println(m);
+ }
+
+ printf ("Virtual function table:\n");
+ for (i = 0; i < c->vftbl->vftbllength; i++)
+ printf ("entry: %d, %ld\n", i, (long int) (c->vftbl->table[i]));
+ }
+ #endif /* !defined(NDEBUG) */
+
+
+ /*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
--- /dev/null
- assert(mi->parseddesc->paramcount == ref->methodref->parseddesc.md->paramcount);
+ /* src/vm/resolve.cpp - resolving classes/interfaces/fields/methods
+
+ Copyright (C) 1996-2005, 2006, 2007, 2008
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+ This file is part of CACAO.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+ */
+
+
+ #include "config.h"
+
+ #include <assert.h>
+
+ #include "vm/types.h"
+
+ #include "mm/memory.h"
+
+ #include "vm/access.h"
+ #include "vm/classcache.h"
+ #include "vm/descriptor.h"
+ #include "vm/exceptions.hpp"
+ #include "vm/global.h"
+ #include "vm/globals.hpp"
+ #include "vm/linker.h"
+ #include "vm/loader.hpp"
+ #include "vm/options.h"
+ #include "vm/primitive.hpp"
+ #include "vm/resolve.hpp"
+
+ #include "vm/jit/jit.hpp"
+ #include "vm/jit/verify/typeinfo.h"
+
+
+ /******************************************************************************/
+ /* DEBUG HELPERS */
+ /******************************************************************************/
+
+ /*#define RESOLVE_VERBOSE*/
+
+ /* resolve_handle_pending_exception ********************************************
+
+ Convert a pending ClassNotFoundException into a
+ NoClassDefFoundError if requested.
+
+ See: hotspot/src/share/vm/classfile/systemDictionary.cpp
+ (handle_resolution_exception)
+
+ ARGUMENTS:
+ classname .... name of the class currently resolved
+ throwError ... if true throw a NoClassDefFoundError instead of
+ a ClassNotFoundException
+
+ *******************************************************************************/
+
+ void resolve_handle_pending_exception(bool throwError)
+ {
+ java_handle_t *e;
+
+ /* Get the current exception. */
+
+ e = exceptions_get_exception();
+
+ if (e != NULL) {
+ if (throwError == true) {
+ /* Convert ClassNotFoundException to
+ NoClassDefFoundError. */
+
+ if (builtin_instanceof(e, class_java_lang_ClassNotFoundException)) {
+ /* Clear exception, because we are calling Java code
+ again. */
+
+ exceptions_clear_exception();
+
+ /* create new error */
+
+ exceptions_throw_noclassdeffounderror_cause(e);
+ }
+ else {
+ return;
+ }
+ }
+ else {
+ /* An exception conversion was not requested. Simply
+ return. */
+
+ return;
+ }
+ }
+ }
+
+
+ /******************************************************************************/
+ /* CLASS RESOLUTION */
+ /******************************************************************************/
+
+ /* resolve_class_from_name *****************************************************
+
+ Resolve a symbolic class reference
+
+ IN:
+ referer..........the class containing the reference
+ refmethod........the method from which resolution was triggered
+ (may be NULL if not applicable)
+ classname........class name to resolve
+ mode.............mode of resolution:
+ resolveLazy...only resolve if it does not
+ require loading classes
+ resolveEager..load classes if necessary
+ checkaccess......if true, access rights to the class are checked
+ link.............if true, guarantee that the returned class, if any,
+ has been linked
+
+ OUT:
+ *result..........set to result of resolution, or to NULL if
+ the reference has not been resolved
+ In the case of an exception, *result is
+ guaranteed to be set to NULL.
+
+ RETURN VALUE:
+ true.............everything ok
+ (*result may still be NULL for resolveLazy)
+ false............an exception has been thrown
+
+ NOTE:
+ The returned class is *not* guaranteed to be linked!
+ (It is guaranteed to be loaded, though.)
+
+ *******************************************************************************/
+
+ bool resolve_class_from_name(classinfo *referer,
+ methodinfo *refmethod,
+ utf *classname,
+ resolve_mode_t mode,
+ bool checkaccess,
+ bool link,
+ classinfo **result)
+ {
+ classinfo *cls;
+ char *utf_ptr;
+ int len;
+ char *msg;
+ s4 msglen;
+ utf *u;
+
+ assert(result);
+ assert(referer);
+ assert(classname);
+ assert(mode == resolveLazy || mode == resolveEager);
+
+ *result = NULL;
+
+ #ifdef RESOLVE_VERBOSE
+ printf("resolve_class_from_name(");
+ utf_fprint_printable_ascii(stdout,referer->name);
+ printf(",%p,",(void*)referer->classloader);
+ utf_fprint_printable_ascii(stdout,classname);
+ printf(",%d,%d)\n",(int)checkaccess,(int)link);
+ #endif
+
+ /* lookup if this class has already been loaded */
+
+ cls = classcache_lookup(referer->classloader, classname);
+
+ #ifdef RESOLVE_VERBOSE
+ printf(" lookup result: %p\n",(void*)cls);
+ #endif
+
+ if (!cls) {
+ /* resolve array types */
+
+ if (classname->text[0] == '[') {
+ utf_ptr = classname->text + 1;
+ len = classname->blength - 1;
+
+ /* classname is an array type name */
+
+ switch (*utf_ptr) {
+ case 'L':
+ utf_ptr++;
+ len -= 2;
+ /* FALLTHROUGH */
+ case '[':
+ /* the component type is a reference type */
+ /* resolve the component type */
+ if (!resolve_class_from_name(referer,refmethod,
+ utf_new(utf_ptr,len),
+ mode,checkaccess,link,&cls))
+ return false; /* exception */
+ if (!cls) {
+ assert(mode == resolveLazy);
+ return true; /* be lazy */
+ }
+ /* create the array class */
+ cls = class_array_of(cls,false);
+ if (!cls)
+ return false; /* exception */
+ }
+ }
+ else {
+ /* the class has not been loaded, yet */
+ if (mode == resolveLazy)
+ return true; /* be lazy */
+ }
+
+ #ifdef RESOLVE_VERBOSE
+ printf(" loading...\n");
+ #endif
+
+ /* load the class */
+
+ if (cls == NULL) {
+ cls = load_class_from_classloader(classname, referer->classloader);
+
+ if (cls == NULL)
+ return false;
+ }
+ }
+
+ /* the class is now loaded */
+ assert(cls);
+ assert(cls->state & CLASS_LOADED);
+
+ #ifdef RESOLVE_VERBOSE
+ printf(" checking access rights...\n");
+ #endif
+
+ /* check access rights of referer to refered class */
+
+ if (checkaccess && !access_is_accessible_class(referer,cls)) {
+ msglen =
+ utf_bytes(cls->name) +
+ utf_bytes(referer->name) +
+ 100;
+
+ msg = MNEW(char, msglen);
+
+ strcpy(msg, "class is not accessible (");
+ utf_cat_classname(msg, cls->name);
+ strcat(msg, " from ");
+ utf_cat_classname(msg, referer->name);
+ strcat(msg, ")");
+
+ u = utf_new_char(msg);
+
+ MFREE(msg, char, msglen);
+
+ exceptions_throw_illegalaccessexception(u);
+
+ return false; /* exception */
+ }
+
+ /* link the class if necessary */
+ if (link) {
+ if (!(cls->state & CLASS_LINKED))
+ if (!link_class(cls))
+ return false; /* exception */
+
+ assert(cls->state & CLASS_LINKED);
+ }
+
+ /* resolution succeeds */
+ #ifdef RESOLVE_VERBOSE
+ printf(" success.\n");
+ #endif
+ *result = cls;
+ return true;
+ }
+
+ /* resolve_classref ************************************************************
+
+ Resolve a symbolic class reference
+
+ IN:
+ refmethod........the method from which resolution was triggered
+ (may be NULL if not applicable)
+ ref..............class reference
+ mode.............mode of resolution:
+ resolveLazy...only resolve if it does not
+ require loading classes
+ resolveEager..load classes if necessary
+ checkaccess......if true, access rights to the class are checked
+ link.............if true, guarantee that the returned class, if any,
+ has been linked
+
+ OUT:
+ *result..........set to result of resolution, or to NULL if
+ the reference has not been resolved
+ In the case of an exception, *result is
+ guaranteed to be set to NULL.
+
+ RETURN VALUE:
+ true.............everything ok
+ (*result may still be NULL for resolveLazy)
+ false............an exception has been thrown
+
+ *******************************************************************************/
+
+ bool resolve_classref(methodinfo *refmethod,
+ constant_classref *ref,
+ resolve_mode_t mode,
+ bool checkaccess,
+ bool link,
+ classinfo **result)
+ {
+ return resolve_classref_or_classinfo(refmethod,CLASSREF_OR_CLASSINFO(ref),mode,checkaccess,link,result);
+ }
+
+ /* resolve_classref_or_classinfo ***********************************************
+
+ Resolve a symbolic class reference if necessary
+
+ NOTE: If given, refmethod->clazz is used as the referring class.
+ Otherwise, cls.ref->referer is used.
+
+ IN:
+ refmethod........the method from which resolution was triggered
+ (may be NULL if not applicable)
+ cls..............class reference or classinfo
+ mode.............mode of resolution:
+ resolveLazy...only resolve if it does not
+ require loading classes
+ resolveEager..load classes if necessary
+ checkaccess......if true, access rights to the class are checked
+ link.............if true, guarantee that the returned class, if any,
+ has been linked
+
+ OUT:
+ *result..........set to result of resolution, or to NULL if
+ the reference has not been resolved
+ In the case of an exception, *result is
+ guaranteed to be set to NULL.
+
+ RETURN VALUE:
+ true.............everything ok
+ (*result may still be NULL for resolveLazy)
+ false............an exception has been thrown
+
+ *******************************************************************************/
+
+ bool resolve_classref_or_classinfo(methodinfo *refmethod,
+ classref_or_classinfo cls,
+ resolve_mode_t mode,
+ bool checkaccess,
+ bool link,
+ classinfo **result)
+ {
+ classinfo *c;
+ classinfo *referer;
+
+ assert(cls.any);
+ assert(mode == resolveEager || mode == resolveLazy);
+ assert(result);
+
+ #ifdef RESOLVE_VERBOSE
+ printf("resolve_classref_or_classinfo(");
+ utf_fprint_printable_ascii(stdout,(IS_CLASSREF(cls)) ? cls.ref->name : cls.cls->name);
+ printf(",%i,%i,%i)\n",mode,(int)checkaccess,(int)link);
+ #endif
+
+ *result = NULL;
+
+ if (IS_CLASSREF(cls)) {
+ /* we must resolve this reference */
+
+ /* determine which class to use as the referer */
+
+ /* Common cases are refmethod == NULL or both referring classes */
+ /* being the same, so the referer usually is cls.ref->referer. */
+ /* There is one important case where it is not: When we do a */
+ /* deferred assignability check to a formal argument of a method, */
+ /* we must use refmethod->clazz (the caller's class) to resolve */
+ /* the type of the formal argument. */
+
+ referer = (refmethod) ? refmethod->clazz : cls.ref->referer;
+
+ if (!resolve_class_from_name(referer, refmethod, cls.ref->name,
+ mode, checkaccess, link, &c))
+ goto return_exception;
+
+ } else {
+ /* cls has already been resolved */
+ c = cls.cls;
+ assert(c->state & CLASS_LOADED);
+ }
+ assert(c || (mode == resolveLazy));
+
+ if (!c)
+ return true; /* be lazy */
+
+ assert(c);
+ assert(c->state & CLASS_LOADED);
+
+ if (link) {
+ if (!(c->state & CLASS_LINKED))
+ if (!link_class(c))
+ goto return_exception;
+
+ assert(c->state & CLASS_LINKED);
+ }
+
+ /* succeeded */
+ *result = c;
+ return true;
+
+ return_exception:
+ *result = NULL;
+ return false;
+ }
+
+
+ /* resolve_classref_or_classinfo_eager *****************************************
+
+ Resolve a symbolic class reference eagerly if necessary.
+ No attempt is made to link the class.
+
+ IN:
+ cls..............class reference or classinfo
+ checkaccess......if true, access rights to the class are checked
+
+ RETURN VALUE:
+ classinfo *......the resolved class
+ NULL.............an exception has been thrown
+
+ *******************************************************************************/
+
+ classinfo *resolve_classref_or_classinfo_eager(classref_or_classinfo cls,
+ bool checkaccess)
+ {
+ classinfo *c;
+
+ if (!resolve_classref_or_classinfo(NULL, cls, resolveEager, checkaccess, false, &c))
+ return NULL;
+
+ return c;
+ }
+
+
+ /* resolve_class_from_typedesc *************************************************
+
+ Return a classinfo * for the given type descriptor
+
+ IN:
+ d................type descriptor
+ checkaccess......if true, access rights to the class are checked
+ link.............if true, guarantee that the returned class, if any,
+ has been linked
+ OUT:
+ *result..........set to result of resolution, or to NULL if
+ the reference has not been resolved
+ In the case of an exception, *result is
+ guaranteed to be set to NULL.
+
+ RETURN VALUE:
+ true.............everything ok
+ false............an exception has been thrown
+
+ NOTE:
+ This function always resolves eagerly.
+
+ *******************************************************************************/
+
+ bool resolve_class_from_typedesc(typedesc *d, bool checkaccess, bool link, classinfo **result)
+ {
+ classinfo *cls;
+
+ assert(d);
+ assert(result);
+
+ *result = NULL;
+
+ #ifdef RESOLVE_VERBOSE
+ printf("resolve_class_from_typedesc(");
+ descriptor_debug_print_typedesc(stdout,d);
+ printf(",%i,%i)\n",(int)checkaccess,(int)link);
+ #endif
+
+ if (d->type == TYPE_ADR) {
+ /* a reference type */
+ assert(d->classref);
+ if (!resolve_classref_or_classinfo(NULL,CLASSREF_OR_CLASSINFO(d->classref),
+ resolveEager,checkaccess,link,&cls))
+ return false; /* exception */
+ }
+ else {
+ /* a primitive type */
+
+ cls = Primitive::get_class_by_type(d->primitivetype);
+
+ assert(cls->state & CLASS_LOADED);
+
+ if (!(cls->state & CLASS_LINKED))
+ if (!link_class(cls))
+ return false; /* exception */
+ }
+
+ assert(cls);
+ assert(cls->state & CLASS_LOADED);
+ assert(!link || (cls->state & CLASS_LINKED));
+
+ #ifdef RESOLVE_VERBOSE
+ printf(" result = ");utf_fprint_printable_ascii(stdout,cls->name);printf("\n");
+ #endif
+
+ *result = cls;
+ return true;
+ }
+
+ /******************************************************************************/
+ /* SUBTYPE SET CHECKS */
+ /******************************************************************************/
+
+ /* 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_t subti;
+ typecheck_result r;
+ char *msg;
+ s4 msglen;
+ utf *u;
+
+ 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) */
+ exceptions_clear_exception();
+ 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 */
+
+ #if defined(RESOLVE_VERBOSE)
+ printf("SUBTYPE CHECK FAILED!\n");
+ #endif
+
+ msglen =
+ utf_bytes(subclass->name) +
+ utf_bytes(CLASSREF_OR_CLASSINFO_NAME(supertype))
+ + 200;
+
+ msg = MNEW(char, msglen);
+
+ strcpy(msg, (error == resolveIllegalAccessError) ?
+ "illegal access to protected member (" :
+ "subtype constraint violated (");
+
+ utf_cat_classname(msg, subclass->name);
+ strcat(msg, " is not a subclass of ");
+ utf_cat_classname(msg, CLASSREF_OR_CLASSINFO_NAME(supertype));
+ strcat(msg, ")");
+
+ u = utf_new_char(msg);
+
+ if (error == resolveIllegalAccessError)
+ exceptions_throw_illegalaccessexception(u);
+ else
+ exceptions_throw_linkageerror(msg, NULL);
+
+ /* ATTENTION: We probably need msg for
+ exceptions_throw_linkageerror. */
+
+ MFREE(msg, 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_t *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)) {
+ exceptions_throw_verifyerror(refmethod,
+ "Invalid use of returnAddress");
+ return resolveFailed;
+ }
+
+ /* uninitialized objects are illegal here */
+
+ if (TYPEINFO_IS_NEWOBJECT(*subtinfo)) {
+ exceptions_throw_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->clazz->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; i<count; ++i) {
+ classref_or_classinfo c = subtinfo->merged->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:
+ refmethod........the method triggering the resolution
+ ref..............a set of class/interface references
+ (may be empty)
+ typeref..........the type to test against the set
+ 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. (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
+ exception which may occurr during resolution may
+ be thrown by this function.
+
+ *******************************************************************************/
+
+ #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;
+ resolve_result_t checkresult;
+
+ assert(refmethod);
+ assert(ref);
+ assert(typeref.any);
+ assert(mode == resolveLazy || mode == resolveEager);
+ assert(error == resolveLinkageError || error == resolveIllegalAccessError);
+
+ #if defined(RESOLVE_VERBOSE)
+ printf("resolve_and_check_subtype_set:\n");
+ unresolved_subtype_set_debug_dump(ref, stdout);
+ if (IS_CLASSREF(typeref))
+ class_classref_println(typeref.ref);
+ else
+ class_println(typeref.cls);
+ #endif
+
+ setp = ref->subtyperefs;
+
+ /* an empty set of tests always succeeds */
+ if (!setp || !setp->any) {
+ return resolveSucceeded;
+ }
+
+ /* 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_t *instanceti,
+ typeinfo_t *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->clazz;
+ assert(referer);
+
+ declarer = fi->clazz;
+ 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_t *insttip;
+ typeinfo_t 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->clazz */
+ 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->clazz;
+ 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);
+ 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->clazz;
+ assert(referer);
+
+ /* check if the field itself is already resolved */
+ if (IS_FMIREF_RESOLVED(ref->fieldref)) {
+ fi = ref->fieldref->p.field;
+ container = fi->clazz;
+ 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);
+ 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->clazz;
+ 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->clazz;
+ assert(referer);
+
+ declarer = mi->clazz;
+ 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,
+ 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->clazz;
+ assert(referer);
+
+ declarer = mi->clazz;
+ 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_t *instanceti,
+ bool invokespecial)
+ {
+ typeinfo_t tinfo;
+ typeinfo_t *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->clazz);
+ tip = &tinfo;
+ if (!typeinfo_init_class(tip, initclass))
+ return resolveFailed;
+ }
+ else {
+ tip = instanceti;
+ }
+
+ result = resolve_lazy_subtype_checks(refmethod,
+ tip,
+ CLASSREF_OR_CLASSINFO(mi->clazz),
+ resolveLinkageError);
+ if (result != resolveSucceeded)
+ return result;
+
+ /* check protected access */
+
+ /* XXX use other `declarer` than mi->clazz? */
+ if (((mi->flags & ACC_PROTECTED) != 0)
+ && !SAME_PACKAGE(mi->clazz, refmethod->clazz))
+ {
+ result = resolve_lazy_subtype_checks(refmethod,
+ tip,
+ CLASSREF_OR_CLASSINFO(refmethod->clazz),
+ 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_t *stack)
+ {
+ typedescriptor_t *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->clazz->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->clazz->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->clazz->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->clazz;
+ 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->clazz;
+ assert(referer);
+
+ /* check if the method itself is already resolved */
+
+ if (IS_FMIREF_RESOLVED(ref->methodref)) {
+ mi = ref->methodref->p.method;
+ container = mi->clazz;
+ 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))
+ {
+ /* the class reference could not be resolved */
+ return false; /* exception */
+ }
+ if (!container)
+ return true; /* be lazy */
+
+ assert(container);
+ 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,
+ ref->methodref->name,
+ ref->methodref->descriptor,
+ referer, true);
+
+ } else {
+ mi = class_resolveclassmethod(container,
+ ref->methodref->name,
+ ref->methodref->descriptor,
+ referer, true);
+ }
+
+ if (!mi) {
+ if (mode == resolveLazy) {
+ /* The method does not exist. But since we were called lazily, */
+ /* this error must not be reported now. (It will be reported */
+ /* if eager resolving of this method is ever tried.) */
+
+ exceptions_clear_exception();
+ return true; /* be lazy */
+ }
+
+ return false; /* exception */ /* XXX set exceptionptr? */
+ }
+
+ /* { the method reference has been resolved } */
+
+ 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. */
+
+ if (!mi->parseddesc->params)
+ if (!descriptor_params_from_paramtypes(mi->parseddesc, mi->flags))
+ return false;
+
+ /* 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,
+ mi,
+ (ref->flags & RESOLVE_STATIC));
+
+ if (checkresult != resolveSucceeded)
+ return (bool) checkresult;
+
+ /* impose loading constraints on params and return type */
+
+ if (!resolve_method_loading_constraints(referer, mi))
+ return false;
+
+ declarer = mi->clazz;
+ 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;
+ }
+
+ /* check subtype constraints for TYPE_ADR parameters */
+
++ assert(mi == ref->methodref->p.method || 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),
+ mode,
+ resolveLinkageError);
+ if (checkresult != resolveSucceeded)
+ return (bool) checkresult;
+ }
+ }
+ }
+
+ /* check protected access */
+
+ if (((mi->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 = mi;
+ return true;
+ }
+
+ /* resolve_method_eager ********************************************************
+
+ Resolve an unresolved method reference eagerly.
+
+ IN:
+ ref..............struct containing the reference
+
+ RETURN VALUE:
+ methodinfo * to the method, or
+ NULL if an exception has been thrown
+
+ *******************************************************************************/
+
+ methodinfo * resolve_method_eager(unresolved_method *ref)
+ {
+ methodinfo *mi;
+
+ if (!resolve_method(ref,resolveEager,&mi))
+ return NULL;
+
+ return mi;
+ }
+
+ /******************************************************************************/
+ /* CREATING THE DATA STRUCTURES */
+ /******************************************************************************/
+
+ #ifdef ENABLE_VERIFIER
+ static bool unresolved_subtype_set_from_typeinfo(classinfo *referer,
+ methodinfo *refmethod,
+ unresolved_subtype_set *stset,
+ typeinfo_t *tinfo,
+ utf *declaredclassname)
+ {
+ int count;
+ int i;
+
+ assert(stset);
+ assert(tinfo);
+
+ #ifdef RESOLVE_VERBOSE
+ printf("unresolved_subtype_set_from_typeinfo\n");
+ #ifdef TYPEINFO_DEBUG
+ typeinfo_print(stdout,tinfo,4);
+ #endif
+ printf(" declared classname:");utf_fprint_printable_ascii(stdout,declaredclassname);
+ printf("\n");
+ #endif
+
+ if (TYPEINFO_IS_PRIMITIVE(*tinfo)) {
+ exceptions_throw_verifyerror(refmethod,
+ "Invalid use of returnAddress");
+ return false;
+ }
+
+ if (TYPEINFO_IS_NEWOBJECT(*tinfo)) {
+ exceptions_throw_verifyerror(refmethod,
+ "Invalid use of uninitialized object");
+ return false;
+ }
+
+ /* the nulltype is always assignable */
+ if (TYPEINFO_IS_NULLTYPE(*tinfo))
+ goto empty_set;
+
+ /* every type is assignable to (BOOTSTRAP)java.lang.Object */
+ if (declaredclassname == utf_java_lang_Object
+ && referer->classloader == NULL) /* XXX do loading constraints make the second check obsolete? */
+ {
+ goto empty_set;
+ }
+
+ if (tinfo->merged) {
+ count = tinfo->merged->count;
+ stset->subtyperefs = MNEW(classref_or_classinfo,count + 1);
+ for (i=0; i<count; ++i) {
+ classref_or_classinfo c = tinfo->merged->list[i];
+ if (tinfo->dimension > 0) {
+ /* a merge of array types */
+ /* the merged list contains the possible _element_ types, */
+ /* so we have to create array types with these elements. */
+ if (IS_CLASSREF(c)) {
+ c.ref = class_get_classref_multiarray_of(tinfo->dimension,c.ref);
+ }
+ else {
+ c.cls = class_multiarray_of(tinfo->dimension,c.cls,false);
+ }
+ }
+ stset->subtyperefs[i] = c;
+ }
+ stset->subtyperefs[count].any = NULL; /* terminate */
+ }
+ else {
+ if ((IS_CLASSREF(tinfo->typeclass)
+ ? tinfo->typeclass.ref->name
+ : tinfo->typeclass.cls->name) == declaredclassname)
+ {
+ /* the class names are the same */
+ /* equality is guaranteed by the loading constraints */
+ goto empty_set;
+ }
+ else {
+ stset->subtyperefs = MNEW(classref_or_classinfo,1 + 1);
+ stset->subtyperefs[0] = tinfo->typeclass;
+ stset->subtyperefs[1].any = NULL; /* terminate */
+ }
+ }
+
+ return true;
+
+ empty_set:
+ UNRESOLVED_SUBTYPE_SET_EMTPY(*stset);
+ return true;
+ }
+ #endif /* ENABLE_VERIFIER */
+
+ /* create_unresolved_class *****************************************************
+
+ Create an unresolved_class struct for the given class reference
+
+ IN:
+ refmethod........the method triggering the resolution (if any)
+ classref.........the class reference
+ valuetype........value type to check against the resolved class
+ may be NULL, if no typeinfo is available
+
+ RETURN VALUE:
+ a pointer to a new unresolved_class struct, or
+ NULL if an exception has been thrown
+
+ *******************************************************************************/
+
+ #ifdef ENABLE_VERIFIER
+ unresolved_class * create_unresolved_class(methodinfo *refmethod,
+ constant_classref *classref,
+ typeinfo_t *valuetype)
+ {
+ unresolved_class *ref;
+
+ #ifdef RESOLVE_VERBOSE
+ printf("create_unresolved_class\n");
+ printf(" referer: ");utf_fprint_printable_ascii(stdout,classref->referer->name);fputc('\n',stdout);
+ if (refmethod) {
+ printf(" rmethod: ");utf_fprint_printable_ascii(stdout,refmethod->name);fputc('\n',stdout);
+ printf(" rmdesc : ");utf_fprint_printable_ascii(stdout,refmethod->descriptor);fputc('\n',stdout);
+ }
+ printf(" name : ");utf_fprint_printable_ascii(stdout,classref->name);fputc('\n',stdout);
+ #endif
+
+ ref = NEW(unresolved_class);
+ ref->classref = classref;
+ ref->referermethod = refmethod;
+
+ if (valuetype) {
+ if (!unresolved_subtype_set_from_typeinfo(classref->referer,refmethod,
+ &(ref->subtypeconstraints),valuetype,classref->name))
+ return NULL;
+ }
+ else {
+ UNRESOLVED_SUBTYPE_SET_EMTPY(ref->subtypeconstraints);
+ }
+
+ return ref;
+ }
+ #endif /* ENABLE_VERIFIER */
+
+ /* resolve_create_unresolved_field *********************************************
+
+ Create an unresolved_field struct for the given field access instruction
+
+ IN:
+ referer..........the class containing the reference
+ refmethod........the method triggering the resolution (if any)
+ iptr.............the {GET,PUT}{FIELD,STATIC}{,CONST} instruction
+
+ RETURN VALUE:
+ a pointer to a new unresolved_field struct, or
+ NULL if an exception has been thrown
+
+ *******************************************************************************/
+
+ unresolved_field * resolve_create_unresolved_field(classinfo *referer,
+ methodinfo *refmethod,
+ instruction *iptr)
+ {
+ unresolved_field *ref;
+ constant_FMIref *fieldref = NULL;
+
+ #ifdef RESOLVE_VERBOSE
+ printf("create_unresolved_field\n");
+ printf(" referer: ");utf_fprint_printable_ascii(stdout,referer->name);fputc('\n',stdout);
+ printf(" rmethod: ");utf_fprint_printable_ascii(stdout,refmethod->name);fputc('\n',stdout);
+ printf(" rmdesc : ");utf_fprint_printable_ascii(stdout,refmethod->descriptor);fputc('\n',stdout);
+ #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
+ /* printf(" class : ");utf_fprint_printable_ascii(stdout,fieldref->p.classref->name);fputc('\n',stdout);*/
+ printf(" name : ");utf_fprint_printable_ascii(stdout,fieldref->name);fputc('\n',stdout);
+ printf(" desc : ");utf_fprint_printable_ascii(stdout,fieldref->descriptor);fputc('\n',stdout);
+ printf(" type : ");descriptor_debug_print_typedesc(stdout,fieldref->parseddesc.fd);
+ fputc('\n',stdout);
+ #endif
+
+ ref->fieldref = fieldref;
+
+ return ref;
+ }
+
+ /* resolve_constrain_unresolved_field ******************************************
+
+ Record subtype constraints for a field access.
+
+ IN:
+ ref..............the unresolved_field structure of the access
+ referer..........the class containing the reference
+ refmethod........the method triggering the resolution (if any)
+ instanceti.......instance typeinfo, if available
+ valueti..........value typeinfo, if available
+
+ RETURN VALUE:
+ true.............everything ok
+ false............an exception has been thrown
+
+ *******************************************************************************/
+
+ #if defined(ENABLE_VERIFIER)
+ bool resolve_constrain_unresolved_field(unresolved_field *ref,
+ classinfo *referer,
+ methodinfo *refmethod,
+ typeinfo_t *instanceti,
+ typeinfo_t *valueti)
+ {
+ constant_FMIref *fieldref;
+ int type;
+ typeinfo_t tinfo;
+ typedesc *fd;
+
+ assert(ref);
+
+ fieldref = ref->fieldref;
+ assert(fieldref);
+
+ #ifdef RESOLVE_VERBOSE
+ printf("constrain_unresolved_field\n");
+ printf(" referer: ");utf_fprint_printable_ascii(stdout,referer->name);fputc('\n',stdout);
+ printf(" rmethod: ");utf_fprint_printable_ascii(stdout,refmethod->name);fputc('\n',stdout);
+ printf(" rmdesc : ");utf_fprint_printable_ascii(stdout,refmethod->descriptor);fputc('\n',stdout);
+ /* printf(" class : ");utf_fprint_printable_ascii(stdout,fieldref->p.classref->name);fputc('\n',stdout); */
+ printf(" name : ");utf_fprint_printable_ascii(stdout,fieldref->name);fputc('\n',stdout);
+ printf(" desc : ");utf_fprint_printable_ascii(stdout,fieldref->descriptor);fputc('\n',stdout);
+ printf(" type : ");descriptor_debug_print_typedesc(stdout,fieldref->parseddesc.fd);
+ fputc('\n',stdout);
+ #endif
+
+ assert(instanceti || ((ref->flags & RESOLVE_STATIC) != 0));
+ fd = fieldref->parseddesc.fd;
+ assert(fd);
+
+ /* record subtype constraints for the instance type, if any */
+ if (instanceti) {
+ typeinfo_t *insttip;
+
+ /* 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 false;
+ }
+ if (TYPEINFO_IS_ARRAY(*instanceti)) {
+ exceptions_throw_verifyerror(refmethod,
+ "illegal instruction: field access on array");
+ return false;
+ }
+
+ if (((ref->flags & RESOLVE_PUTFIELD) != 0) &&
+ 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 false;
+ }
+ /* XXX check that class of field == refmethod->clazz */
+ initclass = refmethod->clazz; /* XXX classrefs */
+ assert(initclass->state & CLASS_LOADED);
+ assert(initclass->state & CLASS_LINKED);
+
+ typeinfo_init_classinfo(&tinfo, initclass);
+ insttip = &tinfo;
+ }
+ else {
+ insttip = instanceti;
+ }
+ if (!unresolved_subtype_set_from_typeinfo(referer, refmethod,
+ &(ref->instancetypes), insttip,
+ FIELDREF_CLASSNAME(fieldref)))
+ return false;
+ }
+ 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)) {
+ assert(valueti);
+ if (!unresolved_subtype_set_from_typeinfo(referer, refmethod,
+ &(ref->valueconstraints), valueti,
+ fieldref->parseddesc.fd->classref->name))
+ return false;
+ }
+ else {
+ UNRESOLVED_SUBTYPE_SET_EMTPY(ref->valueconstraints);
+ }
+
+ return true;
+ }
+ #endif /* ENABLE_VERIFIER */
+
+ /* resolve_create_unresolved_method ********************************************
+
+ Create an unresolved_method struct for the given method invocation
+
+ IN:
+ referer..........the class containing the reference
+ refmethod........the method triggering the resolution (if any)
+ iptr.............the INVOKE* instruction
+
+ RETURN VALUE:
+ a pointer to a new unresolved_method struct, or
+ NULL if an exception has been thrown
+
+ *******************************************************************************/
+
+ unresolved_method * resolve_create_unresolved_method(classinfo *referer,
+ methodinfo *refmethod,
+ constant_FMIref *methodref,
+ bool invokestatic,
+ bool invokespecial)
+ {
+ unresolved_method *ref;
+
+ assert(methodref);
+
+ #ifdef RESOLVE_VERBOSE
+ printf("create_unresolved_method\n");
+ printf(" referer: ");utf_fprint_printable_ascii(stdout,referer->name);fputc('\n',stdout);
+ printf(" rmethod: ");utf_fprint_printable_ascii(stdout,refmethod->name);fputc('\n',stdout);
+ printf(" rmdesc : ");utf_fprint_printable_ascii(stdout,refmethod->descriptor);fputc('\n',stdout);
+ printf(" name : ");utf_fprint_printable_ascii(stdout,methodref->name);fputc('\n',stdout);
+ printf(" desc : ");utf_fprint_printable_ascii(stdout,methodref->descriptor);fputc('\n',stdout);
+ #endif
+
+ /* allocate params if necessary */
+ if (!methodref->parseddesc.md->params)
+ if (!descriptor_params_from_paramtypes(methodref->parseddesc.md,
+ (invokestatic) ? ACC_STATIC : ACC_NONE))
+ return NULL;
+
+ /* create the data structure */
+ ref = NEW(unresolved_method);
+ ref->flags = ((invokestatic) ? RESOLVE_STATIC : 0)
+ | ((invokespecial) ? RESOLVE_SPECIAL : 0);
+ ref->referermethod = refmethod;
+ ref->methodref = methodref;
+ ref->paramconstraints = NULL;
+ UNRESOLVED_SUBTYPE_SET_EMTPY(ref->instancetypes);
+
+ return ref;
+ }
+
+
+ /* resolve_constrain_unresolved_method_instance ********************************
+
+ Record subtype constraints for the instance argument of a method call.
+
+ IN:
+ ref..............the unresolved_method structure of the call
+ referer..........the class containing the reference
+ refmethod........the method triggering the resolution (if any)
+ iptr.............the INVOKE* instruction
+
+ RETURN VALUE:
+ true.............everything ok
+ false............an exception has been thrown
+
+ *******************************************************************************/
+
+ #if defined(ENABLE_VERIFIER)
+ bool resolve_constrain_unresolved_method_instance(unresolved_method *ref,
+ methodinfo *refmethod,
+ typeinfo_t *instanceti,
+ bool invokespecial)
+ {
+ constant_FMIref *methodref;
+ constant_classref *instanceref;
+ typeinfo_t tinfo;
+ typeinfo_t *tip;
+
+ assert(ref);
+ methodref = ref->methodref;
+ assert(methodref);
+
+ /* XXX clean this up */
+ instanceref = IS_FMIREF_RESOLVED(methodref)
+ ? class_get_self_classref(methodref->p.method->clazz)
+ : methodref->p.classref;
+
+ #ifdef RESOLVE_VERBOSE
+ printf("resolve_constrain_unresolved_method_instance\n");
+ printf(" rmethod: "); method_println(refmethod);
+ printf(" mref : "); method_methodref_println(methodref);
+ #endif
+
+ /* record subtype constraints for the instance type, if any */
+
+ 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->clazz);
+ tip = &tinfo;
+ if (!typeinfo_init_class(tip, initclass))
+ return false;
+ }
+ else {
+ tip = instanceti;
+ }
+
+ if (!unresolved_subtype_set_from_typeinfo(refmethod->clazz, refmethod,
+ &(ref->instancetypes),tip,instanceref->name))
+ return false;
+
+ return true;
+ }
+ #endif /* defined(ENABLE_VERIFIER) */
+
+
+ /* resolve_constrain_unresolved_method_params *********************************
+
+ Record subtype constraints for the non-instance arguments of a method call.
+
+ IN:
+ jd...............current jitdata (for looking up variables)
+ ref..............the unresolved_method structure of the call
+ refmethod........the method triggering the resolution (if any)
+ iptr.............the INVOKE* instruction
+
+ RETURN VALUE:
+ true.............everything ok
+ false............an exception has been thrown
+
+ *******************************************************************************/
+
+ #if defined(ENABLE_VERIFIER)
+ bool resolve_constrain_unresolved_method_params(jitdata *jd,
+ unresolved_method *ref,
+ methodinfo *refmethod,
+ instruction *iptr)
+ {
+ constant_FMIref *methodref;
+ varinfo *param;
+ methoddesc *md;
+ int i,j;
+ int type;
+ int instancecount;
+
+ assert(ref);
+ methodref = ref->methodref;
+ assert(methodref);
+ md = methodref->parseddesc.md;
+ assert(md);
+ assert(md->params != NULL);
+
+ #ifdef RESOLVE_VERBOSE
+ printf("resolve_constrain_unresolved_method_params\n");
+ printf(" rmethod: "); method_println(refmethod);
+ printf(" mref : "); method_methodref_println(methodref);
+ #endif
+
+ instancecount = (ref->flags & RESOLVE_STATIC) ? 0 : 1;
+
+ /* record subtype constraints for the parameter types, if any */
+
+ 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) {
+ if (!ref->paramconstraints) {
+ ref->paramconstraints = MNEW(unresolved_subtype_set,md->paramcount);
+ for (j=md->paramcount-1-instancecount; j>i; --j)
+ UNRESOLVED_SUBTYPE_SET_EMTPY(ref->paramconstraints[j]);
+ }
+ assert(ref->paramconstraints);
+ if (!unresolved_subtype_set_from_typeinfo(refmethod->clazz, refmethod,
+ ref->paramconstraints + i,&(param->typeinfo),
+ md->paramtypes[i+instancecount].classref->name))
+ return false;
+ }
+ else {
+ if (ref->paramconstraints)
+ UNRESOLVED_SUBTYPE_SET_EMTPY(ref->paramconstraints[i]);
+ }
+ }
+
+ return true;
+ }
+ #endif /* ENABLE_VERIFIER */
+
+
+ /* resolve_constrain_unresolved_method_params_stackbased ***********************
+
+ Record subtype constraints for the non-instance arguments of a method call.
+
+ IN:
+ ref..............the unresolved_method structure of the call
+ refmethod........the method triggering the resolution (if any)
+ stack............TOS before the INVOKE instruction
+
+ RETURN VALUE:
+ true.............everything ok
+ false............an exception has been thrown
+
+ *******************************************************************************/
+
+ #if defined(ENABLE_VERIFIER)
+ bool resolve_constrain_unresolved_method_params_stackbased(
+ unresolved_method *ref,
+ methodinfo *refmethod,
+ typedescriptor_t *stack)
+ {
+ constant_FMIref *methodref;
+ typedescriptor_t *param;
+ methoddesc *md;
+ int i,j;
+ int type;
+ int instancecount;
+
+ assert(ref);
+ methodref = ref->methodref;
+ assert(methodref);
+ md = methodref->parseddesc.md;
+ assert(md);
+ assert(md->params != NULL);
+
+ #ifdef RESOLVE_VERBOSE
+ printf("resolve_constrain_unresolved_method_params_stackbased\n");
+ printf(" rmethod: "); method_println(refmethod);
+ printf(" mref : "); method_methodref_println(methodref);
+ #endif
+
+ instancecount = (ref->flags & RESOLVE_STATIC) ? 0 : 1;
+
+ /* record subtype constraints for the parameter types, if any */
+
+ 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) {
+ if (!ref->paramconstraints) {
+ ref->paramconstraints = MNEW(unresolved_subtype_set,md->paramcount);
+ for (j = 0; j < i - instancecount; ++j)
+ UNRESOLVED_SUBTYPE_SET_EMTPY(ref->paramconstraints[j]);
+ }
+ assert(ref->paramconstraints);
+ if (!unresolved_subtype_set_from_typeinfo(refmethod->clazz, refmethod,
+ ref->paramconstraints + i - instancecount,&(param->typeinfo),
+ md->paramtypes[i].classref->name))
+ return false;
+ }
+ else {
+ if (ref->paramconstraints)
+ UNRESOLVED_SUBTYPE_SET_EMTPY(ref->paramconstraints[i]);
+ }
+
+ param += (IS_2_WORD_TYPE(type)) ? 2 : 1;
+ }
+
+ return true;
+ }
+ #endif /* ENABLE_VERIFIER */
+
+
+ /******************************************************************************/
+ /* FREEING MEMORY */
+ /******************************************************************************/
+
+ #ifdef ENABLE_VERIFIER
+ inline static void unresolved_subtype_set_free_list(classref_or_classinfo *list)
+ {
+ if (list) {
+ classref_or_classinfo *p = list;
+
+ /* this is silly. we *only* need to count the elements for MFREE */
+ while ((p++)->any)
+ ;
+ MFREE(list,classref_or_classinfo,(p - list));
+ }
+ }
+ #endif /* ENABLE_VERIFIER */
+
+ /* unresolved_class_free *******************************************************
+
+ Free the memory used by an unresolved_class
+
+ IN:
+ ref..............the unresolved_class
+
+ *******************************************************************************/
+
+ void unresolved_class_free(unresolved_class *ref)
+ {
+ assert(ref);
+
+ #ifdef ENABLE_VERIFIER
+ unresolved_subtype_set_free_list(ref->subtypeconstraints.subtyperefs);
+ #endif
+ FREE(ref,unresolved_class);
+ }
+
+ /* unresolved_field_free *******************************************************
+
+ Free the memory used by an unresolved_field
+
+ IN:
+ ref..............the unresolved_field
+
+ *******************************************************************************/
+
+ void unresolved_field_free(unresolved_field *ref)
+ {
+ assert(ref);
+
+ #ifdef ENABLE_VERIFIER
+ unresolved_subtype_set_free_list(ref->instancetypes.subtyperefs);
+ unresolved_subtype_set_free_list(ref->valueconstraints.subtyperefs);
+ #endif
+ FREE(ref,unresolved_field);
+ }
+
+ /* unresolved_method_free ******************************************************
+
+ Free the memory used by an unresolved_method
+
+ IN:
+ ref..............the unresolved_method
+
+ *******************************************************************************/
+
+ void unresolved_method_free(unresolved_method *ref)
+ {
+ assert(ref);
+
+ #ifdef ENABLE_VERIFIER
+ unresolved_subtype_set_free_list(ref->instancetypes.subtyperefs);
+ if (ref->paramconstraints) {
+ int i;
+ int count = ref->methodref->parseddesc.md->paramcount;
+
+ for (i=0; i<count; ++i)
+ unresolved_subtype_set_free_list(ref->paramconstraints[i].subtyperefs);
+ MFREE(ref->paramconstraints,unresolved_subtype_set,count);
+ }
+ #endif
+ FREE(ref,unresolved_method);
+ }
+
+ /******************************************************************************/
+ /* DEBUG DUMPS */
+ /******************************************************************************/
+
+ #if !defined(NDEBUG)
+
+ /* unresolved_subtype_set_debug_dump *******************************************
+
+ Print debug info for unresolved_subtype_set to stream
+
+ IN:
+ stset............the unresolved_subtype_set
+ file.............the stream
+
+ *******************************************************************************/
+
+ 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");
+ }
+ else {
+ p = stset->subtyperefs;
+ for (;p->any; ++p) {
+ if (IS_CLASSREF(*p)) {
+ fprintf(file," ref: ");
+ utf_fprint_printable_ascii(file,p->ref->name);
+ }
+ else {
+ fprintf(file," cls: ");
+ utf_fprint_printable_ascii(file,p->cls->name);
+ }
+ fputc('\n',file);
+ }
+ }
+ }
+
+ /* unresolved_class_debug_dump *************************************************
+
+ Print debug info for unresolved_class to stream
+
+ IN:
+ ref..............the unresolved_class
+ file.............the stream
+
+ *******************************************************************************/
+
+ void unresolved_class_debug_dump(unresolved_class *ref,FILE *file)
+ {
+ fprintf(file,"unresolved_class(%p):\n",(void *)ref);
+ if (ref) {
+ fprintf(file," referer : ");
+ utf_fprint_printable_ascii(file,ref->classref->referer->name); fputc('\n',file);
+ fprintf(file," refmethod : ");
+ utf_fprint_printable_ascii(file,ref->referermethod->name); fputc('\n',file);
+ fprintf(file," refmethodd: ");
+ utf_fprint_printable_ascii(file,ref->referermethod->descriptor); fputc('\n',file);
+ fprintf(file," classname : ");
+ utf_fprint_printable_ascii(file,ref->classref->name); fputc('\n',file);
+ fprintf(file," subtypeconstraints:\n");
+ unresolved_subtype_set_debug_dump(&(ref->subtypeconstraints),file);
+ }
+ }
+
+ /* unresolved_field_debug_dump *************************************************
+
+ Print debug info for unresolved_field to stream
+
+ IN:
+ ref..............the unresolved_field
+ file.............the stream
+
+ *******************************************************************************/
+
+ 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_printable_ascii(file,ref->referermethod->clazz->name); fputc('\n',file);
+ fprintf(file," refmethod : ");
+ utf_fprint_printable_ascii(file,ref->referermethod->name); fputc('\n',file);
+ fprintf(file," refmethodd: ");
+ utf_fprint_printable_ascii(file,ref->referermethod->descriptor); fputc('\n',file);
+ fprintf(file," classname : ");
+ utf_fprint_printable_ascii(file,FIELDREF_CLASSNAME(ref->fieldref)); fputc('\n',file);
+ fprintf(file," name : ");
+ utf_fprint_printable_ascii(file,ref->fieldref->name); fputc('\n',file);
+ fprintf(file," descriptor: ");
+ 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);
+ fprintf(file," instancetypes:\n");
+ unresolved_subtype_set_debug_dump(&(ref->instancetypes),file);
+ fprintf(file," valueconstraints:\n");
+ unresolved_subtype_set_debug_dump(&(ref->valueconstraints),file);
+ }
+ }
+
+ /* unresolved_method_debug_dump ************************************************
+
+ Print debug info for unresolved_method to stream
+
+ IN:
+ ref..............the unresolved_method
+ file.............the stream
+
+ *******************************************************************************/
+
+ void unresolved_method_debug_dump(unresolved_method *ref,FILE *file)
+ {
+ int i;
+
+ fprintf(file,"unresolved_method(%p):\n",(void *)ref);
+ if (ref) {
+ fprintf(file," referer : ");
+ utf_fprint_printable_ascii(file,ref->referermethod->clazz->name); fputc('\n',file);
+ fprintf(file," refmethod : ");
+ utf_fprint_printable_ascii(file,ref->referermethod->name); fputc('\n',file);
+ fprintf(file," refmethodd: ");
+ utf_fprint_printable_ascii(file,ref->referermethod->descriptor); fputc('\n',file);
+ fprintf(file," classname : ");
+ utf_fprint_printable_ascii(file,METHODREF_CLASSNAME(ref->methodref)); fputc('\n',file);
+ fprintf(file," name : ");
+ utf_fprint_printable_ascii(file,ref->methodref->name); fputc('\n',file);
+ fprintf(file," descriptor: ");
+ 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);
+ fprintf(file," instancetypes:\n");
+ unresolved_subtype_set_debug_dump(&(ref->instancetypes),file);
+ fprintf(file," paramconstraints:\n");
+ if (ref->paramconstraints) {
+ for (i=0; i<ref->methodref->parseddesc.md->paramcount; ++i) {
+ fprintf(file," param %d:\n",i);
+ unresolved_subtype_set_debug_dump(ref->paramconstraints + i,file);
+ }
+ }
+ else {
+ fprintf(file," (empty)\n");
+ }
+ }
+ }
+ #endif /* !defined(NDEBUG) */
+
+
+ /*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */