-/* vm/class.c - class related functions
+/* src/vm/class.c - class related functions
Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
Andreas Krall
Christian Thalinger
- $Id: class.c 2104 2005-03-28 22:34:15Z twisti $
+ $Id: class.c 3807 2005-11-26 21:51:11Z edwin $
*/
#include <string.h>
#include "config.h"
-#include "types.h"
+#include "vm/types.h"
#include "mm/memory.h"
#include "toolbox/logging.h"
#include "vm/class.h"
+#include "vm/classcache.h"
+#include "vm/exceptions.h"
+#include "vm/global.h"
#include "vm/loader.h"
#include "vm/options.h"
+#include "vm/resolve.h"
#include "vm/statistics.h"
+#include "vm/stringlocal.h"
#include "vm/tables.h"
#include "vm/utf8.h"
#define CLASS_ASSERT(cond)
#endif
-/* global variables ***********************************************************/
-hashtable class_hash; /* hashtable for classes */
+/* global variables ***********************************************************/
list unlinkedclasses; /* this is only used for eager class */
/* loading */
/* important system classes */
-classinfo *class_java_lang_Object;
-classinfo *class_java_lang_Class;
-classinfo *class_java_lang_ClassLoader;
-classinfo *class_java_lang_Cloneable;
-classinfo *class_java_lang_SecurityManager;
-classinfo *class_java_lang_String;
-classinfo *class_java_lang_System;
-classinfo *class_java_io_Serializable;
+classinfo *class_java_lang_Object = NULL;
+classinfo *class_java_lang_Class = NULL;
+classinfo *class_java_lang_ClassLoader = NULL;
+classinfo *class_java_lang_Cloneable = NULL;
+classinfo *class_java_lang_SecurityManager = NULL;
+classinfo *class_java_lang_String = NULL;
+classinfo *class_java_lang_System = NULL;
+classinfo *class_java_lang_Thread = NULL;
+classinfo *class_java_lang_ThreadGroup = NULL;
+classinfo *class_java_lang_VMThread = NULL;
+classinfo *class_java_io_Serializable = NULL;
/* system exception classes required in cacao */
-classinfo *class_java_lang_Throwable;
-classinfo *class_java_lang_VMThrowable;
-classinfo *class_java_lang_Exception;
-classinfo *class_java_lang_Error;
-classinfo *class_java_lang_OutOfMemoryError;
+classinfo *class_java_lang_Throwable = NULL;
+classinfo *class_java_lang_VMThrowable = NULL;
+classinfo *class_java_lang_Error = NULL;
+classinfo *class_java_lang_NoClassDefFoundError = NULL;
+classinfo *class_java_lang_LinkageError = NULL;
+classinfo *class_java_lang_NoSuchMethodError = NULL;
+classinfo *class_java_lang_OutOfMemoryError = NULL;
+classinfo *class_java_lang_Exception = NULL;
+classinfo *class_java_lang_ClassNotFoundException = NULL;
+classinfo *class_java_lang_IllegalArgumentException = NULL;
+classinfo *class_java_lang_IllegalMonitorStateException = NULL;
-classinfo *class_java_lang_Void;
-classinfo *class_java_lang_Boolean;
-classinfo *class_java_lang_Byte;
-classinfo *class_java_lang_Character;
-classinfo *class_java_lang_Short;
-classinfo *class_java_lang_Integer;
-classinfo *class_java_lang_Long;
-classinfo *class_java_lang_Float;
-classinfo *class_java_lang_Double;
+classinfo *class_java_lang_Void = NULL;
+classinfo *class_java_lang_Boolean = NULL;
+classinfo *class_java_lang_Byte = NULL;
+classinfo *class_java_lang_Character = NULL;
+classinfo *class_java_lang_Short = NULL;
+classinfo *class_java_lang_Integer = NULL;
+classinfo *class_java_lang_Long = NULL;
+classinfo *class_java_lang_Float = NULL;
+classinfo *class_java_lang_Double = NULL;
-/* some classes which may be used more often */
-classinfo *class_java_util_Vector;
+/* some runtime exception */
+classinfo *class_java_lang_NullPointerException = NULL;
-/* pseudo classes for the typechecker */
-classinfo *pseudo_class_Arraystub;
-classinfo *pseudo_class_Null;
-classinfo *pseudo_class_New;
+/* some classes which may be used more often */
+classinfo *class_java_lang_StackTraceElement = NULL;
+classinfo *class_java_lang_reflect_Constructor = NULL;
+classinfo *class_java_lang_reflect_Field = NULL;
+classinfo *class_java_lang_reflect_Method = NULL;
+classinfo *class_java_security_PrivilegedAction = NULL;
+classinfo *class_java_util_Vector = NULL;
-/* class_init ******************************************************************
+classinfo *arrayclass_java_lang_Object = NULL;
- Initialize the class subsystem.
-*******************************************************************************/
+/* pseudo classes for the typechecker */
-void class_init_foo(void)
-{
- class_java_lang_Object = class_new_intern(utf_java_lang_Object);
-
- class_java_lang_Class = class_new(utf_java_lang_Class);
- class_java_lang_ClassLoader = class_new(utf_java_lang_ClassLoader);
- class_java_lang_Cloneable = class_new(utf_java_lang_Cloneable);
- class_java_lang_SecurityManager = class_new(utf_java_lang_SecurityManager);
- class_java_lang_String = class_new(utf_java_lang_String);
- class_java_lang_System = class_new(utf_java_lang_System);
- class_java_io_Serializable = class_new(utf_java_io_Serializable);
-
- class_java_lang_Throwable = class_new(utf_java_lang_Throwable);
- class_java_lang_VMThrowable = class_new(utf_java_lang_VMThrowable);
- class_java_lang_Exception = class_new(utf_java_lang_Exception);
- class_java_lang_Error = class_new(utf_java_lang_Error);
- class_java_lang_OutOfMemoryError =
- class_new(utf_java_lang_OutOfMemoryError);
-
- class_java_lang_Void = class_new(utf_java_lang_Void);
- class_java_lang_Boolean = class_new(utf_java_lang_Boolean);
- class_java_lang_Byte = class_new(utf_java_lang_Byte);
- class_java_lang_Character = class_new(utf_java_lang_Character);
- class_java_lang_Short = class_new(utf_java_lang_Short);
- class_java_lang_Integer = class_new(utf_java_lang_Integer);
- class_java_lang_Long = class_new(utf_java_lang_Long);
- class_java_lang_Float = class_new(utf_java_lang_Float);
- class_java_lang_Double = class_new(utf_java_lang_Double);
-
- class_java_util_Vector = class_new(utf_java_util_Vector);
-
- pseudo_class_Arraystub = class_new_intern(utf_new_char("$ARRAYSTUB$"));
- pseudo_class_Null = class_new_intern(utf_new_char("$NULL$"));
- pseudo_class_New = class_new_intern(utf_new_char("$NEW$"));
-}
+classinfo *pseudo_class_Arraystub = NULL;
+classinfo *pseudo_class_Null = NULL;
+classinfo *pseudo_class_New = NULL;
-/* class_new *******************************************************************
+/* class_set_packagename *******************************************************
- Searches for the class with the specified name in the classes
- hashtable, if there is no such class a new classinfo structure is
- created and inserted into the list of classes to be loaded.
+ Derive the package name from the class name and store it in the struct.
*******************************************************************************/
-classinfo *class_new(utf *classname)
+void class_set_packagename(classinfo *c)
{
- classinfo *c;
-
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
- tables_lock();
-#endif
-
- c = class_new_intern(classname);
+ char *p = UTF_END(c->name) - 1;
+ char *start = c->name->text;
- /* we support eager class loading and linking on demand */
+ /* set the package name */
+ /* classes in the unnamed package keep packagename == NULL */
- if (opt_eager) {
- classinfo *tc;
- classinfo *tmp;
+ if (c->name->text[0] == '[') {
+ /* set packagename of arrays to the element's package */
- list_init(&unlinkedclasses, OFFSET(classinfo, listnode));
+ for (; *start == '['; start++);
- if (!c->loaded) {
- if (!class_load(c)) {
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
- tables_unlock();
-#endif
- return c;
- }
- }
+ /* skip the 'L' in arrays of references */
+ if (*start == 'L')
+ start++;
- /* link all referenced classes */
+ for (; (p > start) && (*p != '/'); --p);
- tc = list_first(&unlinkedclasses);
+ c->packagename = utf_new(start, p - start);
- while (tc) {
- /* skip the current loaded/linked class */
- if (tc != c) {
- if (!class_link(tc)) {
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
- tables_unlock();
-#endif
- return c;
- }
- }
-
- /* we need a tmp variable here, because list_remove sets prev and
- next to NULL */
- tmp = list_next(&unlinkedclasses, tc);
- list_remove(&unlinkedclasses, tc);
- tc = tmp;
- }
+ } else {
+ for (; (p > start) && (*p != '/'); --p);
- if (!c->linked) {
- if (!class_link(c)) {
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
- tables_unlock();
-#endif
- return c;
- }
- }
+ c->packagename = utf_new(start, p - start);
}
-
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
- tables_unlock();
-#endif
-
- return c;
}
-classinfo *class_new_intern(utf *classname)
-{
- classinfo *c; /* hashtable element */
- u4 key; /* hashkey computed from classname */
- u4 slot; /* slot in hashtable */
- u2 i;
+/* class_create_classinfo ******************************************************
- key = utf_hashkey(classname->text, classname->blength);
- slot = key & (class_hash.size - 1);
- c = class_hash.ptr[slot];
+ Create a new classinfo struct. The class name is set to the given utf *,
+ most other fields are initialized to zero.
- /* search external hash chain for the class */
- while (c) {
- if (c->name->blength == classname->blength) {
- for (i = 0; i < classname->blength; i++)
- if (classname->text[i] != c->name->text[i]) goto nomatch;
-
- /* class found in hashtable */
- return c;
- }
-
- nomatch:
- c = c->hashlink; /* next element in external chain */
- }
+ 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.
+
+*******************************************************************************/
- /* location in hashtable found, create new classinfo structure */
+classinfo *class_create_classinfo(utf *classname)
+{
+ classinfo *c;
#if defined(STATISTICS)
if (opt_stat)
count_class_infos += sizeof(classinfo);
#endif
- if (initverbose) {
- char logtext[MAXLOGTEXT];
- sprintf(logtext, "Creating class: ");
- utf_sprint_classname(logtext + strlen(logtext), classname);
- log_text(logtext);
- }
+ /* we use a safe name for temporarily unnamed classes */
+ if (!classname)
+ classname = utf_not_named_yet;
- c = GCNEW(classinfo, 1); /*JOWENN: NEW*/
- /*c=NEW(classinfo);*/
- c->vmClass = 0;
- c->flags = 0;
- c->name = classname;
- c->packagename = NULL;
- c->cpcount = 0;
- c->cptags = NULL;
- c->cpinfos = NULL;
- c->classrefs = NULL;
- c->extclassrefs = NULL;
- c->classrefcount = 0;
- c->parseddescs = NULL;
- c->parseddescsize = 0;
- c->super = NULL;
- c->sub = NULL;
- c->nextsub = NULL;
- c->interfacescount = 0;
- c->interfaces = NULL;
- c->fieldscount = 0;
- c->fields = NULL;
- c->methodscount = 0;
- c->methods = NULL;
- c->linked = false;
- c->loaded = false;
- c->index = 0;
- c->instancesize = 0;
- c->header.vftbl = NULL;
- c->innerclasscount = 0;
- c->innerclass = NULL;
- c->vftbl = NULL;
- c->initialized = false;
- c->initializing = false;
- c->classvftbl = false;
- c->classUsed = 0;
- c->impldBy = NULL;
- c->classloader = NULL;
- c->sourcefile = NULL;
-
- /* insert class into the hashtable */
- c->hashlink = class_hash.ptr[slot];
- class_hash.ptr[slot] = c;
+ if (initverbose)
+ log_message_utf("Creating class: ", classname);
- /* update number of hashtable-entries */
- class_hash.entries++;
+ /* GCNEW_UNCOLLECTABLE clears the allocated memory */
- if (class_hash.entries > (class_hash.size * 2)) {
-
- /* reorganization of hashtable, average length of
- the external chains is approx. 2 */
-
- u4 i;
- classinfo *c;
- hashtable newhash; /* the new hashtable */
-
- /* create new hashtable, double the size */
- init_hashtable(&newhash, class_hash.size * 2);
- newhash.entries = class_hash.entries;
+ c = GCNEW_UNCOLLECTABLE(classinfo, 1);
+ /*c=NEW(classinfo);*/
+ c->name = classname;
- /* transfer elements to new hashtable */
- for (i = 0; i < class_hash.size; i++) {
- c = (classinfo *) class_hash.ptr[i];
- while (c) {
- classinfo *nextc = c->hashlink;
- u4 slot = (utf_hashkey(c->name->text, c->name->blength)) & (newhash.size - 1);
-
- c->hashlink = newhash.ptr[slot];
- newhash.ptr[slot] = c;
+ /* set the header.vftbl of all loaded classes to the one of
+ java.lang.Class, so Java code can use a class as object */
- c = nextc;
- }
- }
+ if (class_java_lang_Class)
+ if (class_java_lang_Class->vftbl)
+ c->header.vftbl = class_java_lang_Class->vftbl;
- /* dispose old table */
- MFREE(class_hash.ptr, void*, class_hash.size);
- class_hash = newhash;
- }
-
- /* Array classes need further initialization. */
- if (c->name->text[0] == '[') {
- /* Array classes are not loaded from classfiles. */
- c->loaded = true;
- class_new_array(c);
- c->packagename = array_packagename;
-
- } else {
- /* Find the package name */
- /* Classes in the unnamed package keep packagename == NULL. */
- char *p = utf_end(c->name) - 1;
- char *start = c->name->text;
- for (;p > start; --p) {
- if (*p == '/') {
- c->packagename = utf_new (start, p - start);
- break;
- }
- }
- }
+ if (classname != utf_not_named_yet)
+ class_set_packagename(c);
#if defined(USE_THREADS) && defined(NATIVE_THREADS)
initObjectLock(&c->header);
}
-/* class_get *******************************************************************
+/* class_postset_header_vftbl **************************************************
- Searches for the class with the specified name in the classes
- hashtable if there is no such class NULL is returned.
+ 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.
*******************************************************************************/
-classinfo *class_get(utf *classname)
+void class_postset_header_vftbl(void)
{
- classinfo *c; /* hashtable element */
- u4 key; /* hashkey computed from classname */
- u4 slot; /* slot in hashtable */
- u2 i;
-
- key = utf_hashkey(classname->text, classname->blength);
- slot = key & (class_hash.size-1);
- c = class_hash.ptr[slot];
-
- /* search external hash-chain */
- while (c) {
- if (c->name->blength == classname->blength) {
- /* compare classnames */
- for (i = 0; i < classname->blength; i++)
- if (classname->text[i] != c->name->text[i])
- goto nomatch;
-
- /* class found in hashtable */
- return c;
- }
-
- nomatch:
- c = c->hashlink;
- }
-
- /* class not found */
- return NULL;
-}
-
-
-/* class_remove ****************************************************************
+ classinfo *c;
+ u4 slot;
+ classcache_name_entry *nmen;
+ classcache_class_entry *clsen;
- Removes the class entry wth the specified name in the classes
- hashtable, furthermore the class' resources are freed if there is
- no such class false is returned.
+ assert(class_java_lang_Class);
-*******************************************************************************/
+ for (slot = 0; slot < classcache_hash.size; slot++) {
+ nmen = (classcache_name_entry *) classcache_hash.ptr[slot];
-bool class_remove(classinfo *c)
-{
- classinfo *tc; /* hashtable element */
- classinfo *pc;
- u4 key; /* hashkey computed from classname */
- u4 slot; /* slot in hashtable */
- u2 i;
-
- key = utf_hashkey(c->name->text, c->name->blength);
- slot = key & (class_hash.size - 1);
- tc = class_hash.ptr[slot];
- pc = NULL;
-
- /* search external hash-chain */
- while (tc) {
- if (tc->name->blength == c->name->blength) {
-
- /* compare classnames */
- for (i = 0; i < c->name->blength; i++)
- if (tc->name->text[i] != c->name->text[i])
- goto nomatch;
+ for (; nmen; nmen = nmen->hashlink) {
+ /* iterate over all class entries */
- /* class found in hashtable */
- if (!pc)
- class_hash.ptr[slot] = tc->hashlink;
- else
- pc->hashlink = tc->hashlink;
+ for (clsen = nmen->classes; clsen; clsen = clsen->next) {
+ c = clsen->classobj;
- class_free(tc);
+ /* now set the the vftbl */
- return true;
+ if (c->header.vftbl == NULL)
+ c->header.vftbl = class_java_lang_Class->vftbl;
+ }
}
-
- nomatch:
- pc = tc;
- tc = tc->hashlink;
}
-
- /* class not found */
- return false;
}
}
+/* 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.
+
+*******************************************************************************/
+
+voidptr 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) {
+ *exceptionptr = new_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.
+
+*******************************************************************************/
+
+voidptr innerclass_getconstant(classinfo *c, u4 pos, u4 ctype)
+{
+ /* invalid position in constantpool */
+ if (pos >= c->cpcount) {
+ *exceptionptr = new_classformaterror(c, "Illegal constant pool index");
+ return NULL;
+ }
+
+ /* constantpool entry of type 0 */
+ if (!c->cptags[pos])
+ return NULL;
+
+ /* check type of constantpool entry */
+ if (c->cptags[pos] != ctype) {
+ *exceptionptr = new_classformaterror(c, "Illegal constant pool index");
+ return NULL;
+ }
+
+ return c->cpinfos[pos];
+}
+
+
/* class_free ******************************************************************
Frees all resources used by the class.
}
+/* 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,java_objectheader *initloader,
+ java_objectheader *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;
+ }
+
+ CLASS_ASSERT(c);
+ CLASS_ASSERT(c->loaded);
+ CLASS_ASSERT(c->classloader == defloader);
+
+ if (link && !c->linked)
+ if (!link_class(c))
+ return NULL;
+
+ CLASS_ASSERT(!link || c->linked);
+
+ return c;
+}
+
+
/* class_array_of **************************************************************
Returns an array class with the given component class. The array
*******************************************************************************/
-classinfo *class_array_of(classinfo *component)
+classinfo *class_array_of(classinfo *component, bool link)
{
s4 namelen;
char *namebuf;
- classinfo *c;
/* Assemble the array class name */
namelen = component->name->blength;
namelen += 3;
}
- c = class_new(utf_new(namebuf, namelen));
-
- /* load this class ;-) and link it */
-
- if (!c->loaded)
- c->loaded = true;
-
- if (!c->linked)
- if (!class_link(c))
- return NULL;
-
- return c;
+ return get_array_class(utf_new(namebuf, namelen),
+ component->classloader,
+ component->classloader,
+ link);
}
*******************************************************************************/
-classinfo *class_multiarray_of(s4 dim, classinfo *element)
+classinfo *class_multiarray_of(s4 dim, classinfo *element, bool link)
{
s4 namelen;
char *namebuf;
- if (dim < 1)
- panic("Invalid array dimension requested");
+ if (dim < 1) {
+ log_text("Invalid array dimension requested");
+ assert(0);
+ }
/* Assemble the array class name */
namelen = element->name->blength;
}
memset(namebuf, '[', dim);
- return class_new(utf_new(namebuf, namelen));
+ return get_array_class(utf_new(namebuf, namelen),
+ element->classloader,
+ element->classloader,
+ link);
}
+
/* class_lookup_classref *******************************************************
Looks up the constant_classref for a given classname in the classref
*******************************************************************************/
-constant_classref *class_lookup_classref(classinfo *cls,utf *name)
+constant_classref *class_lookup_classref(classinfo *cls, utf *name)
{
constant_classref *ref;
extra_classref *xref;
return ref;
/* next try the list of extra classrefs */
- for (xref=cls->extclassrefs; xref; xref=xref->next) {
+ for (xref = cls->extclassrefs; xref; xref = xref->next) {
if (xref->classref.name == name)
return &(xref->classref);
}
*******************************************************************************/
-constant_classref *class_get_classref(classinfo *cls,utf *name)
+constant_classref *class_get_classref(classinfo *cls, utf *name)
{
constant_classref *ref;
extra_classref *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
*******************************************************************************/
-constant_classref *class_get_classref_multiarray_of(s4 dim,constant_classref *ref)
+constant_classref *class_get_classref_multiarray_of(s4 dim, constant_classref *ref)
{
s4 namelen;
char *namebuf;
return class_get_classref(ref->referer,utf_new(namebuf, namelen));
}
+
/* class_get_classref_component_of *********************************************
Returns the component classref of a given array type reference
return NULL;
}
- return class_get_classref(ref->referer,utf_new(name, namelen));
+ 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;
+}
+
+
+/************************* Function: class_findmethod_approx ******************
+
+ like class_findmethod but ignores the return value when comparing the
+ descriptor.
+
+*******************************************************************************/
+
+methodinfo *class_findmethod_approx(classinfo *c, utf *name, utf *desc)
+{
+ s4 i;
+
+ for (i = 0; i < c->methodscount; i++) {
+ if (c->methods[i].name == name) {
+ utf *meth_descr = c->methods[i].descriptor;
+
+ if (desc == NULL)
+ /* ignore type */
+ return &(c->methods[i]);
+
+ if (desc->blength <= meth_descr->blength) {
+ /* current position in utf text */
+ char *desc_utf_ptr = desc->text;
+ char *meth_utf_ptr = meth_descr->text;
+ /* points behind utf strings */
+ char *desc_end = UTF_END(desc);
+ char *meth_end = UTF_END(meth_descr);
+ char ch;
+
+ /* compare argument types */
+ while (desc_utf_ptr < desc_end && meth_utf_ptr < meth_end) {
+
+ if ((ch = *desc_utf_ptr++) != (*meth_utf_ptr++))
+ break; /* no match */
+
+ if (ch == ')')
+ return &(c->methods[i]); /* all parameter types equal */
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+/* class_resolvemethod *********************************************************
+
+ Searches a class and it's super classes for a method.
+
+ Superinterfaces are *not* searched.
+
+*******************************************************************************/
+
+methodinfo *class_resolvemethod(classinfo *c, utf *name, utf *desc)
+{
+ methodinfo *m;
+
+ while (c) {
+ m = class_findmethod(c, name, desc);
+
+ if (m)
+ return m;
+
+ /* JVM Specification bug:
+
+ It is important NOT to resolve special <init> and <clinit>
+ methods to super classes or interfaces; yet, this is not
+ explicited in the specification. Section 5.4.3.3 should be
+ updated appropriately. */
+
+ if (name == utf_init || name == utf_clinit)
+ return NULL;
+
+ c = c->super.cls;
+ }
+
+ 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;
+
+ m = class_findmethod(c, name, desc);
+
+ if (m)
+ return m;
+
+ /* try the superinterfaces */
+
+ for (i = 0; i < c->interfacescount; i++) {
+ m = class_resolveinterfacemethod_intern(c->interfaces[i].cls,
+ name, desc);
+
+ if (m)
+ return m;
+ }
+
+ 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 except)
+{
+ classinfo *cls;
+ methodinfo *m;
+ s4 i;
+
+ /* XXX resolve class c */
+ /* XXX check access from REFERER to C */
+
+/* if (c->flags & ACC_INTERFACE) { */
+/* if (except) */
+/* *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)
+ goto found;
+
+ /* try the superinterfaces */
+
+ for (i = 0; i < c->interfacescount; i++) {
+ m = class_resolveinterfacemethod_intern(c->interfaces[i].cls,
+ name, desc);
+
+ if (m)
+ goto found;
+ }
+
+ if (except)
+ *exceptionptr = exceptions_new_nosuchmethoderror(c, name, desc);
+
+ return NULL;
+
+ found:
+ if ((m->flags & ACC_ABSTRACT) && !(c->flags & ACC_ABSTRACT)) {
+ if (except)
+ *exceptionptr = new_exception(string_java_lang_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 except)
+{
+ methodinfo *mi;
+
+ /* XXX resolve class c */
+ /* XXX check access from REFERER to C */
+
+ if (!(c->flags & ACC_INTERFACE)) {
+ if (except)
+ *exceptionptr =
+ new_exception(string_java_lang_IncompatibleClassChangeError);
+
+ return NULL;
+ }
+
+ mi = class_resolveinterfacemethod_intern(c, name, desc);
+
+ if (mi)
+ return mi;
+
+ /* try class java.lang.Object */
+
+ mi = class_findmethod(class_java_lang_Object, name, desc);
+
+ if (mi)
+ return mi;
+
+ if (except)
+ *exceptionptr =
+ exceptions_new_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.cls)
+ return class_findfield(c->super.cls, 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)
+{
+ s4 i;
+
+ /* get field index */
+
+ i = class_findfield_index_by_name(c, name);
+
+ /* field was not found, return */
+
+ if (i == -1)
+ return NULL;
+
+ /* return field address */
+
+ return &(c->fields[i]);
+}
+
+
+s4 class_findfield_index_by_name(classinfo *c, utf *name)
+{
+ s4 i;
+
+ for (i = 0; i < c->fieldscount; i++) {
+ /* compare field names */
+
+ if ((c->fields[i].name == name))
+ return i;
+ }
+
+ /* field was not found, raise exception */
+
+ *exceptionptr = new_exception(string_java_lang_NoSuchFieldException);
+
+ return -1;
+}
+
+
+/****************** 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 superinterfaces recursively */
+
+ for (i = 0; i < c->interfacescount; i++) {
+ fi = class_resolvefield_int(c->interfaces[i].cls, name, desc);
+ if (fi)
+ return fi;
+ }
+
+ /* try superclass */
+
+ if (c->super.cls)
+ return class_resolvefield_int(c->super.cls, 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 the return value is NULL. If EXCEPT is
+ true *exceptionptr is set, too.
+
+*******************************************************************************/
+
+fieldinfo *class_resolvefield(classinfo *c, utf *name, utf *desc,
+ classinfo *referer, bool except)
+{
+ fieldinfo *fi;
+
+ /* XXX resolve class c */
+ /* XXX check access from REFERER to C */
+
+ fi = class_resolvefield_int(c, name, desc);
+
+ if (!fi) {
+ if (except)
+ *exceptionptr =
+ new_exception_utfmessage(string_java_lang_NoSuchFieldError,
+ 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)
+{
+ for (;;) {
+ if (!sub)
+ return false;
+
+ if (sub == super)
+ return true;
+
+ sub = sub->super.cls;
+ }
+}
+
+
+void class_showconstanti(classinfo *c, int ii)
+{
+ u4 i = ii;
+ voidptr e;
+
+ e = c->cpinfos [i];
+ printf ("#%d: ", (int) i);
+ if (e) {
+ switch (c->cptags [i]) {
+ case CONSTANT_Class:
+ printf("Classreference -> ");
+ utf_display(((constant_classref*)e)->name);
+ break;
+
+ case CONSTANT_Fieldref:
+ printf("Fieldref -> "); goto displayFMIi;
+ case CONSTANT_Methodref:
+ printf("Methodref -> "); goto displayFMIi;
+ case CONSTANT_InterfaceMethodref:
+ printf("InterfaceMethod -> "); goto displayFMIi;
+ displayFMIi:
+ {
+ constant_FMIref *fmi = e;
+ utf_display(fmi->classref->name);
+ printf(".");
+ utf_display(fmi->name);
+ printf(" ");
+ utf_display(fmi->descriptor);
+ }
+ break;
+
+ case CONSTANT_String:
+ printf("String -> ");
+ utf_display(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:
+ {
+ u8 v = ((constant_long*)e)->value;
+#if U8_AVAILABLE
+ printf("Long -> %ld", (long int) v);
+#else
+ printf("Long -> HI: %ld, LO: %ld\n",
+ (long int) v.high, (long int) v.low);
+#endif
+ }
+ break;
+ case CONSTANT_NameAndType:
+ {
+ constant_nameandtype *cnt = e;
+ printf("NameAndType: ");
+ utf_display(cnt->name);
+ printf(" ");
+ utf_display(cnt->descriptor);
+ }
+ break;
+ case CONSTANT_Utf8:
+ printf("Utf8 -> ");
+ utf_display(e);
+ break;
+ default:
+ log_text("Invalid type of ConstantPool-Entry");
+ assert(0);
+ }
+ }
+ printf("\n");
+}
+
+
+void class_showconstantpool (classinfo *c)
+{
+ u4 i;
+ voidptr e;
+
+ printf ("---- dump of constant pool ----\n");
+
+ for (i=0; i<c->cpcount; i++) {
+ printf ("#%d: ", (int) i);
+
+ e = c -> cpinfos [i];
+ if (e) {
+
+ switch (c -> cptags [i]) {
+ case CONSTANT_Class:
+ printf ("Classreference -> ");
+ utf_display ( ((constant_classref*)e) -> name );
+ break;
+
+ case CONSTANT_Fieldref:
+ printf ("Fieldref -> "); goto displayFMI;
+ case CONSTANT_Methodref:
+ printf ("Methodref -> "); goto displayFMI;
+ case CONSTANT_InterfaceMethodref:
+ printf ("InterfaceMethod -> "); goto displayFMI;
+ displayFMI:
+ {
+ constant_FMIref *fmi = e;
+ utf_display ( fmi->classref->name );
+ printf (".");
+ utf_display ( fmi->name);
+ printf (" ");
+ utf_display ( fmi->descriptor );
+ }
+ break;
+
+ case CONSTANT_String:
+ printf ("String -> ");
+ utf_display (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:
+ {
+ u8 v = ((constant_long*)e) -> value;
+#if U8_AVAILABLE
+ printf ("Long -> %ld", (long int) v);
+#else
+ printf ("Long -> HI: %ld, LO: %ld\n",
+ (long int) v.high, (long int) v.low);
+#endif
+ }
+ break;
+ case CONSTANT_NameAndType:
+ {
+ constant_nameandtype *cnt = e;
+ printf ("NameAndType: ");
+ utf_display (cnt->name);
+ printf (" ");
+ utf_display (cnt->descriptor);
+ }
+ break;
+ case CONSTANT_Utf8:
+ printf ("Utf8 -> ");
+ utf_display (e);
+ break;
+ default:
+ log_text("Invalid type of ConstantPool-Entry");
+ assert(0);
+ }
+ }
+
+ printf ("\n");
+ }
+}
+
+
+
+/********** Function: class_showmethods (debugging only) *************/
+
+void class_showmethods (classinfo *c)
+{
+ s4 i;
+
+ printf ("--------- Fields and Methods ----------------\n");
+ printf ("Flags: "); printflags (c->flags); printf ("\n");
+
+ printf ("This: "); utf_display (c->name); printf ("\n");
+ if (c->super.cls) {
+ printf ("Super: "); utf_display (c->super.cls->name); printf ("\n");
+ }
+ printf ("Index: %d\n", c->index);
+
+ printf ("interfaces:\n");
+ for (i=0; i < c-> interfacescount; i++) {
+ printf (" ");
+ utf_display (c -> interfaces[i].cls -> name);
+ printf (" (%d)\n", c->interfaces[i].cls -> index);
+ }
+
+ printf ("fields:\n");
+ for (i=0; i < c -> fieldscount; i++) {
+ field_display (&(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_display ( 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]) );
+ }
+
}