From: Robert Schuster Date: Fri, 10 Oct 2008 14:18:16 +0000 (+0200) Subject: * merged default branch into jitcache-arm-x86 branch X-Git-Url: http://wien.tomnetworks.com/gitweb/?p=cacao.git;a=commitdiff_plain;h=0698bb7e6153d5892e5ccdb9d9770999b1e1c217 * merged default branch into jitcache-arm-x86 branch --HG-- branch : jitcache-arm-x86 rename : src/vm/class.c => src/vm/class.cpp rename : src/vm/class.h => src/vm/class.hpp rename : src/vm/resolve.c => src/vm/resolve.cpp --- 0698bb7e6153d5892e5ccdb9d9770999b1e1c217 diff --cc src/vm/class.cpp index 000000000,6444cbb67..1e479529b mode 000000,100644..100644 --- a/src/vm/class.cpp +++ b/src/vm/class.cpp @@@ -1,0 -1,2455 +1,2464 @@@ + /* 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 + #include + #include + #include + + #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 and + 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 . */ + + 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 */ + + 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; icpcount; 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: + */ diff --cc src/vm/class.hpp index 000000000,c82e4bf24..f643fd357 mode 000000,100644..100644 --- a/src/vm/class.hpp +++ b/src/vm/class.hpp @@@ -1,0 -1,460 +1,462 @@@ + /* src/vm/class.hpp - class related functions header + + 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. + + */ + + + #ifndef _CLASS_HPP + #define _CLASS_HPP + + /* forward typedefs ***********************************************************/ + + typedef struct classinfo classinfo; + typedef struct innerclassinfo innerclassinfo; + typedef struct extra_classref extra_classref; + + + #include "config.h" + + #include + + #include "vm/types.h" + + #if defined(ENABLE_JAVASE) + # include "vm/annotation.h" + #endif + + #include "vm/field.hpp" + #include "vm/global.h" + #include "vm/linker.h" + #include "vm/loader.hpp" + #include "vm/method.h" + #include "vm/references.h" + #include "vm/string.hpp" + #include "vm/utf8.h" + - + /* class state defines ********************************************************/ + + #define CLASS_LOADING 0x0001 + #define CLASS_LOADED 0x0002 + #define CLASS_LINKING 0x0004 + #define CLASS_LINKED 0x0008 + #define CLASS_INITIALIZING 0x0010 + #define CLASS_INITIALIZED 0x0020 + #define CLASS_ERROR 0x0040 + + + /* some macros ****************************************************************/ + + #define CLASS_IS_OR_ALMOST_INITIALIZED(c) \ + (((c)->state & CLASS_INITIALIZING) || ((c)->state & CLASS_INITIALIZED)) + + + /* classinfo ******************************************************************/ + + /* We define this dummy structure of java_lang_Class so we can + bootstrap cacaoh without needing a java_lang_Class.h file. Whether + the size of the dummy structure is big enough is checked during + runtime in vm_create. */ + + typedef struct { + java_object_t header; + #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH) + intptr_t padding[4]; + #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) + intptr_t padding[19]; + #elif defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1) + intptr_t padding[3]; + #else + # error unknown classpath configuration + #endif + } dummy_java_lang_Class; + + struct classinfo { /* class structure */ + dummy_java_lang_Class object; + + s4 flags; /* ACC flags */ + utf *name; /* class name */ + + s4 cpcount; /* number of entries in constant pool */ + u1 *cptags; /* constant pool tags */ + void* *cpinfos; /* pointer to constant pool info structures */ + + s4 classrefcount; /* number of symbolic class references */ + constant_classref *classrefs; /* table of symbolic class references */ + extra_classref *extclassrefs; /* additional classrefs */ + s4 parseddescsize; /* size of the parsed descriptors block */ + u1 *parseddescs; /* parsed descriptors */ + + classinfo *super; /* super class */ + classinfo *sub; /* sub class pointer */ + classinfo *nextsub; /* pointer to next class in sub class list */ + + int32_t interfacescount; /* number of interfaces */ + classinfo **interfaces; /* super interfaces */ + + int32_t fieldscount; /* number of fields */ + fieldinfo *fields; /* field table */ + + int32_t methodscount; /* number of methods */ + methodinfo *methods; /* method table */ + + s4 state; /* current class state */ + s4 index; /* hierarchy depth (classes) or index */ + /* (interfaces) */ + s4 instancesize; /* size of an instance of this class */ + + vftbl_t *vftbl; /* pointer to virtual function table */ + + methodinfo *finalizer; /* finalizer method */ + + u2 innerclasscount; /* number of inner classes */ + innerclassinfo *innerclass; + + classref_or_classinfo declaringclass; + classref_or_classinfo enclosingclass; /* enclosing class */ + constant_nameandtype *enclosingmethod; /* enclosing method */ + + utf *packagename; /* full name of the package */ + utf *sourcefile; /* SourceFile attribute */ + #if defined(ENABLE_JAVASE) + utf *signature; /* Signature attribute */ + #if defined(ENABLE_ANNOTATIONS) + /* All the annotation attributes are NULL (and not a zero length array) */ + /* if there is nothing. */ + java_object_t *annotations; /* annotations of this class */ + + java_object_t *method_annotations; /* array of annotations of the methods */ + java_object_t *method_parameterannotations; /* array of parameter */ + /* annotations of the methods */ + java_object_t *method_annotationdefaults; /* array of annotation default */ + /* values of the methods */ + + java_object_t *field_annotations; /* array of annotations of the fields */ + + #endif + #endif + classloader_t *classloader; /* NULL for bootstrap classloader */ + + #if defined(ENABLE_JAVASE) + # if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) + java_object_t *protectiondomain; + java_objectarray_t *signers; + # endif + #endif ++#if defined(ENABLE_JITCACHE) ++ int cache_file_fd; ++#endif + }; + + + /* innerclassinfo *************************************************************/ + + struct innerclassinfo { + classref_or_classinfo inner_class; /* inner class pointer */ + classref_or_classinfo outer_class; /* outer class pointer */ + utf *name; /* innerclass name */ + s4 flags; /* ACC flags */ + }; + + + /* extra_classref ************************************************************** + + for classrefs not occurring within descriptors + + *******************************************************************************/ + + struct extra_classref { + extra_classref *next; + constant_classref classref; + }; + + + /* inline functions ***********************************************************/ + + #ifdef __cplusplus + extern "C" { + #endif + + /** + * Returns the classname of the class, where slashes ('/') are + * replaced by dots ('.'). + * + * @param c class to get name of + * @return classname + */ + inline static java_handle_t* class_get_classname(classinfo* c) + { + java_handle_t *s; + + /* Create a java string. */ + + s = javastring_new_slash_to_dot(c->name); + + return s; + } + + + /* class_is_primitive ********************************************************** + + Checks if the given class is a primitive class. + + *******************************************************************************/ + + static inline bool class_is_primitive(classinfo *c) + { + if (c->flags & ACC_CLASS_PRIMITIVE) + return true; + + return false; + } + + + /* class_is_anonymousclass ***************************************************** + + Checks if the given class is an anonymous class. + + *******************************************************************************/ + + static inline bool class_is_anonymousclass(classinfo *c) + { + if (c->flags & ACC_CLASS_ANONYMOUS) + return true; + + return false; + } + + + /* class_is_array ************************************************************** + + Checks if the given class is an array class. + + *******************************************************************************/ + + static inline bool class_is_array(classinfo *c) + { + if (!(c->state & CLASS_LINKED)) + if (!link_class(c)) + return false; + + return (c->vftbl->arraydesc != NULL); + } + + + /* class_is_interface ********************************************************** + + Checks if the given class is an interface. + + *******************************************************************************/ + + static inline bool class_is_interface(classinfo *c) + { + if (c->flags & ACC_INTERFACE) + return true; + + return false; + } + + + /* class_is_localclass ********************************************************* + + Checks if the given class is a local class. + + *******************************************************************************/ + + static inline bool class_is_localclass(classinfo *c) + { + if ((c->enclosingmethod != NULL) && !class_is_anonymousclass(c)) + return true; + + return false; + } + + + /* class_is_memberclass ******************************************************** + + Checks if the given class is a member class. + + *******************************************************************************/ + + static inline bool class_is_memberclass(classinfo *c) + { + if (c->flags & ACC_CLASS_MEMBER) + return true; + + return false; + } + + + /* class_get_classloader ******************************************************* + + Return the classloader of the given class. + + *******************************************************************************/ + + static inline classloader_t *class_get_classloader(classinfo *c) + { + classloader_t *cl; + + cl = c->classloader; + + /* The classloader may be NULL. */ + + return cl; + } + + + /* class_get_superclass ******************************************************** + + Return the super class of the given class. + + *******************************************************************************/ + + static inline classinfo *class_get_superclass(classinfo *c) + { + /* For interfaces we return NULL. */ + + if (c->flags & ACC_INTERFACE) + return NULL; + + /* For java/lang/Object, primitive-type and Void classes c->super + is NULL and we return NULL. */ + + return c->super; + } + + + /* function prototypes ********************************************************/ + + classinfo *class_create_classinfo(utf *u); + void class_postset_header_vftbl(void); + classinfo *class_define(utf *name, classloader_t *cl, int32_t length, uint8_t *data, java_handle_t *pd); + void class_set_packagename(classinfo *c); + + bool class_load_attributes(classbuffer *cb); + + /* retrieve constantpool element */ + void* class_getconstant(classinfo *c, u4 pos, u4 ctype); + void* innerclass_getconstant(classinfo *c, u4 pos, u4 ctype); + + /* frees all resources used by the class */ + void class_free(classinfo *); + + /* return an array class with the given component class */ + classinfo *class_array_of(classinfo *component,bool link); + + /* return an array class with the given dimension and element class */ + classinfo *class_multiarray_of(s4 dim, classinfo *element,bool link); + + /* return a classref for the given class name */ + /* (does a linear search!) */ + constant_classref *class_lookup_classref(classinfo *cls,utf *name); + + /* return a classref for the given class name */ + /* (does a linear search!) */ + constant_classref *class_get_classref(classinfo *cls,utf *name); + + /* return a classref to the class itself */ + /* (does a linear search!) */ + constant_classref *class_get_self_classref(classinfo *cls); + + /* return a classref for an array with the given dimension of with the */ + /* given component type */ + constant_classref *class_get_classref_multiarray_of(s4 dim,constant_classref *ref); + + /* return a classref for the component type of the given array type */ + constant_classref *class_get_classref_component_of(constant_classref *ref); + + /* get a class' field by name and descriptor */ + fieldinfo *class_findfield(classinfo *c, utf *name, utf *desc); + + /* search 'classinfo'-structure for a field with the specified name */ + fieldinfo *class_findfield_by_name(classinfo *c, utf *name); + + /* search class for a field */ + fieldinfo *class_resolvefield(classinfo *c, utf *name, utf *desc, classinfo *referer); + + /* search for a method with a specified name and descriptor */ + methodinfo *class_findmethod(classinfo *c, utf *name, utf *desc); + methodinfo *class_resolvemethod(classinfo *c, utf *name, utf *dest); + methodinfo *class_resolveclassmethod(classinfo *c, utf *name, utf *dest, classinfo *referer, bool throwexception); + methodinfo *class_resolveinterfacemethod(classinfo *c, utf *name, utf *dest, classinfo *referer, bool throwexception); + + bool class_issubclass(classinfo *sub, classinfo *super); + bool class_isanysubclass(classinfo *sub, classinfo *super); + bool class_is_assignable_from(classinfo *to, classinfo *from); + bool class_is_instance(classinfo *c, java_handle_t *h); + + classloader_t *class_get_classloader(classinfo *c); + classinfo *class_get_superclass(classinfo *c); + classinfo *class_get_componenttype(classinfo *c); + java_handle_objectarray_t *class_get_declaredclasses(classinfo *c, bool publicOnly); + java_handle_objectarray_t *class_get_declaredconstructors(classinfo *c, bool publicOnly); + java_handle_objectarray_t *class_get_declaredfields(classinfo *c, bool publicOnly); + java_handle_objectarray_t *class_get_declaredmethods(classinfo *c, bool publicOnly); + classinfo *class_get_declaringclass(classinfo *c); + classinfo *class_get_enclosingclass(classinfo *c); + java_handle_t* class_get_enclosingconstructor(classinfo *c); + methodinfo* class_get_enclosingmethod_raw(classinfo *c); + java_handle_t* class_get_enclosingmethod(classinfo *c); + java_handle_objectarray_t *class_get_interfaces(classinfo *c); + java_handle_bytearray_t *class_get_annotations(classinfo *c); + int32_t class_get_modifiers(classinfo *c, bool ignoreInnerClassesAttrib); + java_handle_t *class_get_name(classinfo *c); + + #if defined(ENABLE_JAVASE) + utf *class_get_signature(classinfo *c); + #endif + + /* some debugging functions */ + + #if !defined(NDEBUG) + void class_printflags(classinfo *c); + void class_print(classinfo *c); + void class_println(classinfo *c); + void class_classref_print(constant_classref *cr); + void class_classref_println(constant_classref *cr); + void class_classref_or_classinfo_print(classref_or_classinfo c); + void class_classref_or_classinfo_println(classref_or_classinfo c); + #endif + + /* debug purposes */ + void class_showmethods(classinfo *c); + void class_showconstantpool(classinfo *c); + + #ifdef __cplusplus + } + #endif + + #endif /* _CLASS_HPP */ + + + /* + * 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: + */ diff --cc src/vm/options.c index f1c085114,3c3bace70..962e98f4b --- a/src/vm/options.c +++ b/src/vm/options.c @@@ -160,11 -160,9 +160,12 @@@ int opt_ThreadStackSiz /* Debugging options which can be turned off. */ + bool opt_AlwaysEmitLongBranches = false; int opt_DebugExceptions = 0; int opt_DebugFinalizer = 0; +#if defined(ENABLE_JITCACHE) +int opt_DebugJitCache = 0; +#endif int opt_DebugLocalReferences = 0; int opt_DebugLocks = 0; int opt_DebugPackage = 0; @@@ -233,9 -231,9 +234,10 @@@ enum /* Debugging options which can be turned off. */ + OPT_AlwaysEmitLongBranches, OPT_DebugExceptions, OPT_DebugFinalizer, + OPT_DebugJitCache, OPT_DebugLocalReferences, OPT_DebugLocks, OPT_DebugPackage, @@@ -287,11 -285,9 +289,12 @@@ option_t options_XX[] = /* Debugging options which can be turned off. */ + { "AlwaysEmitLongBranches", OPT_AlwaysEmitLongBranches, OPT_TYPE_BOOLEAN, "Always emit long-branches." }, { "DebugExceptions", OPT_DebugExceptions, OPT_TYPE_BOOLEAN, "debug exceptions" }, { "DebugFinalizer", OPT_DebugFinalizer, OPT_TYPE_BOOLEAN, "debug finalizer thread" }, +#if defined (ENABLE_JITCACHE) + { "DebugJitCache", OPT_DebugJitCache, OPT_TYPE_BOOLEAN, "debug JIT cache actions" }, +#endif { "DebugLocalReferences", OPT_DebugLocalReferences, OPT_TYPE_BOOLEAN, "print debug information for local reference tables" }, { "DebugLocks", OPT_DebugLocks, OPT_TYPE_BOOLEAN, "print debug information for locks" }, { "DebugPackage", OPT_DebugPackage, OPT_TYPE_BOOLEAN, "debug Java boot-packages" }, diff --cc src/vm/options.h index 0861d0e6f,1758add5c..460f595dc --- a/src/vm/options.h +++ b/src/vm/options.h @@@ -182,11 -182,9 +182,12 @@@ extern int opt_ThreadStackSize /* Debugging options which can be turned off. */ + extern bool opt_AlwaysEmitLongBranches; extern int opt_DebugExceptions; extern int opt_DebugFinalizer; +#if defined(ENABLE_JITCACHE) +extern int opt_DebugJitCache; +#endif extern int opt_DebugLocalReferences; extern int opt_DebugLocks; extern int opt_DebugPatcher; diff --cc src/vm/resolve.cpp index 000000000,1d1173a87..cdd42a733 mode 000000,100644..100644 --- a/src/vm/resolve.cpp +++ b/src/vm/resolve.cpp @@@ -1,0 -1,3164 +1,3164 @@@ + /* 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 + + #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; imerged->list[i]; + if (subtinfo->dimension > 0) { + /* a merge of array types */ + /* the merged list contains the possible _element_ types, */ + /* so we have to create array types with these elements. */ + if (IS_CLASSREF(c)) { + c.ref = class_get_classref_multiarray_of(subtinfo->dimension,c.ref); + } + else { + c.cls = class_multiarray_of(subtinfo->dimension,c.cls,false); + } + } + + /* do the subtype check against the type c */ + + result = resolve_subtype_check(refmethod,c,supertype,resolveLazy,error); + if (result != resolveSucceeded) + return result; + } + } + else { + + /* a single type, this is the common case, hopefully */ + + if (CLASSREF_OR_CLASSINFO_NAME(subtinfo->typeclass) + == CLASSREF_OR_CLASSINFO_NAME(supertype)) + { + /* the class names are the same */ + /* equality is guaranteed by the loading constraints */ + return resolveSucceeded; + } + else { + + /* some other type name, try to perform the check lazily */ + + return resolve_subtype_check(refmethod, + subtinfo->typeclass,supertype, + resolveLazy, + error); + } + } + + /* everything ok */ + return resolveSucceeded; + } + #endif /* defined(ENABLE_VERIFIER) */ + + /* resolve_and_check_subtype_set *********************************************** + + Resolve the references in the given set and test subtype relationships + + IN: + 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 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->parseddesc->paramcount == ref->methodref->parseddesc.md->paramcount); ++ 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; imerged->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; iparamconstraints[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; imethodref->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: + */ diff --cc src/vm/statistics.c index 46aa681f7,c23a737cc..8ab2f6fd5 --- a/src/vm/statistics.c +++ b/src/vm/statistics.c @@@ -46,9 -46,7 +46,9 @@@ #include "toolbox/logging.h" +#include "threads/thread.hpp" + - #include "vm/class.h" + #include "vm/class.hpp" #include "vm/field.hpp" #include "vm/global.h" #include "vm/method.h"