* src/vm/jit/mips/asmpart.S (asm_abstractmethoderror): New function.
[cacao.git] / src / vm / class.c
index 82e8d98bdb2da0f3688a29d62e98d2b135cc3ede..81b5453479b8f1e961de3dd6e1e81c1ac6c35a4d 100644 (file)
@@ -1,9 +1,9 @@
 /* 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,
-   C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
-   Institut f. Computersprachen - TU Wien
+   Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
+   C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
+   E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
+   J. Wenninger, Institut f. Computersprachen - TU Wien
 
    This file is part of CACAO.
 
 
    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., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
 
-   Contact: cacao@complang.tuwien.ac.at
+   Contact: cacao@cacaojvm.org
 
    Authors: Reinhard Grafl
 
    Changes: Mark Probst
             Andreas Krall
             Christian Thalinger
+                       Edwin Steiner
 
-   $Id: class.c 3497 2005-10-26 15:00:20Z twisti $
+   $Id: class.c 5053 2006-06-28 19:11:20Z twisti $
 
 */
 
+
+#include "config.h"
+
 #include <assert.h>
+#include <stdio.h>
 #include <string.h>
 
-#include "config.h"
 #include "vm/types.h"
 
 #include "mm/memory.h"
 
-#if defined(USE_THREADS)
-# if defined(NATIVE_THREADS)
-#  include "threads/native/threads.h"
-# else
-#  include "threads/green/threads.h"
-#  include "threads/green/locks.h"
-# endif
+#if defined(ENABLE_THREADS)
+# include "threads/native/threads.h"
 #endif
 
 #include "toolbox/logging.h"
@@ -61,7 +60,6 @@
 #include "vm/resolve.h"
 #include "vm/statistics.h"
 #include "vm/stringlocal.h"
-#include "vm/tables.h"
 #include "vm/utf8.h"
 
 
@@ -90,64 +88,68 @@ list unlinkedclasses;                   /* this is only used for eager class  */
 
 /* important system classes */
 
-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;
+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_lang_Thread;
+classinfo *class_java_lang_ThreadGroup;
+classinfo *class_java_lang_VMThread;
+classinfo *class_java_io_Serializable;
 
 
 /* system exception classes required in cacao */
 
-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_OutOfMemoryError = NULL;
-
-classinfo *class_java_lang_Exception = NULL;
-classinfo *class_java_lang_ClassNotFoundException = NULL;
-classinfo *class_java_lang_IllegalArgumentException = NULL;
-
-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;
+classinfo *class_java_lang_Throwable;
+classinfo *class_java_lang_VMThrowable;
+classinfo *class_java_lang_Error;
+classinfo *class_java_lang_AbstractMethodError;
+classinfo *class_java_lang_LinkageError;
+classinfo *class_java_lang_NoClassDefFoundError;
+classinfo *class_java_lang_NoSuchMethodError;
+classinfo *class_java_lang_OutOfMemoryError;
+
+classinfo *class_java_lang_Exception;
+classinfo *class_java_lang_ClassNotFoundException;
+classinfo *class_java_lang_IllegalArgumentException;
+classinfo *class_java_lang_IllegalMonitorStateException;
+
+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;
 
 
 /* some runtime exception */
 
-classinfo *class_java_lang_NullPointerException = NULL;
+classinfo *class_java_lang_NullPointerException;
 
 
 /* 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;
+classinfo *class_java_lang_StackTraceElement;
+classinfo *class_java_lang_reflect_Constructor;
+classinfo *class_java_lang_reflect_Field;
+classinfo *class_java_lang_reflect_Method;
+classinfo *class_java_security_PrivilegedAction;
+classinfo *class_java_util_Vector;
 
-classinfo *arrayclass_java_lang_Object = NULL;
+classinfo *arrayclass_java_lang_Object;
 
 
 /* pseudo classes for the typechecker */
 
-classinfo *pseudo_class_Arraystub = NULL;
-classinfo *pseudo_class_Null = NULL;
-classinfo *pseudo_class_New = NULL;
+classinfo *pseudo_class_Arraystub;
+classinfo *pseudo_class_Null;
+classinfo *pseudo_class_New;
 
 
 /* class_set_packagename *******************************************************
@@ -200,7 +202,7 @@ classinfo *class_create_classinfo(utf *classname)
 {
        classinfo *c;
 
-#if defined(STATISTICS)
+#if defined(ENABLE_STATISTICS)
        if (opt_stat)
                count_class_infos += sizeof(classinfo);
 #endif
@@ -209,26 +211,71 @@ classinfo *class_create_classinfo(utf *classname)
        if (!classname)
                classname = utf_not_named_yet;
 
+#if !defined(NDEBUG)
        if (initverbose)
                log_message_utf("Creating class: ", classname);
+#endif
 
        /* GCNEW_UNCOLLECTABLE clears the allocated memory */
 
        c = GCNEW_UNCOLLECTABLE(classinfo, 1);
        /*c=NEW(classinfo);*/
        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)
+               if (class_java_lang_Class->vftbl)
+                       c->object.header.vftbl = class_java_lang_Class->vftbl;
        
-       if (classname != utf_not_named_yet) {
+       if (classname != utf_not_named_yet)
                class_set_packagename(c);
-       }
 
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-       initObjectLock(&c->header);
+#if defined(ENABLE_THREADS)
+       lock_init_object_lock(&c->object.header);
 #endif
 
        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_freepool **************************************************************
 
        Frees all resources used by this classes Constant Pool.
@@ -414,14 +461,14 @@ static classinfo *get_array_class(utf *name,java_objectheader *initloader,
        }
 
        CLASS_ASSERT(c);
-       CLASS_ASSERT(c->loaded);
+       CLASS_ASSERT(c->state & CLASS_LOADED);
        CLASS_ASSERT(c->classloader == defloader);
 
-       if (link && !c->linked)
+       if (link && !(c->state & CLASS_LINKED))
                if (!link_class(c))
                        return NULL;
 
-       CLASS_ASSERT(!link || c->linked);
+       CLASS_ASSERT(!link || (c->state & CLASS_LINKED));
 
        return c;
 }
@@ -657,6 +704,7 @@ constant_classref *class_get_classref_multiarray_of(s4 dim, constant_classref *r
     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
@@ -697,6 +745,204 @@ constant_classref *class_get_classref_component_of(constant_classref *ref)
 }
 
 
+/* class_findmethod ************************************************************
+       
+   Searches a 'classinfo' structure for a method having the given name
+   and descriptor. If descriptor is NULL, it is ignored.
+
+*******************************************************************************/
+
+methodinfo *class_findmethod(classinfo *c, utf *name, utf *desc)
+{
+       methodinfo *m;
+       s4          i;
+
+       for (i = 0; i < c->methodscount; i++) {
+               m = &(c->methods[i]);
+
+               if ((m->name == name) && ((desc == NULL) || (m->descriptor == desc)))
+                       return m;
+       }
+
+       return NULL;
+}
+
+
+/* class_resolvemethod *********************************************************
+       
+   Searches a class and it's super classes for a method.
+
+   Superinterfaces are *not* searched.
+
+*******************************************************************************/
+
+methodinfo *class_resolvemethod(classinfo *c, utf *name, utf *desc)
+{
+       methodinfo *m;
+
+       while (c) {
+               m = class_findmethod(c, name, desc);
+
+               if (m)
+                       return m;
+
+               /* JVM Specification bug: 
+
+                  It is important NOT to resolve special <init> and <clinit>
+                  methods to super classes or interfaces; yet, this is not
+                  explicited in the specification.  Section 5.4.3.3 should be
+                  updated appropriately.  */
+
+               if (name == utf_init || name == utf_clinit)
+                       return NULL;
+
+               c = c->super.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;
+
+       /* try to find the method in the class */
+
+       m = class_findmethod(c, name, desc);
+
+       if (m != NULL)
+               return m;
+
+       /* no method found? try the superinterfaces */
+
+       for (i = 0; i < c->interfacescount; i++) {
+               m = class_resolveinterfacemethod_intern(c->interfaces[i].cls,
+                                                                                                       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 superinterfaces */
+
+       for (i = 0; i < c->interfacescount; i++) {
+               m = class_resolveinterfacemethod_intern(c->interfaces[i].cls,
+                                                                                               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)
+                       *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 (throwexception)
+               *exceptionptr =
+                       exceptions_new_nosuchmethoderror(c, name, desc);
+
+       return NULL;
+}
+
+
 /* class_findfield *************************************************************
        
    Searches for field with specified name and type in a classinfo
@@ -730,16 +976,18 @@ fieldinfo *class_findfield_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 &(c->fields[i]);
-       }
+       /* get field index */
 
-       /* field was not found, raise exception */      
-       *exceptionptr = new_exception(string_java_lang_NoSuchFieldException);
+       i = class_findfield_index_by_name(c, name);
 
-       return NULL;
+       /* field was not found, return */
+
+       if (i == -1)
+               return NULL;
+
+       /* return field address */
+
+       return &(c->fields[i]);
 }
 
 
@@ -749,17 +997,357 @@ s4 class_findfield_index_by_name(classinfo *c, utf *name)
 
        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 throwexception)
+{
+       fieldinfo *fi;
+
+       fi = class_resolvefield_int(c, name, desc);
+
+       if (!fi) {
+               if (throwexception)
+                       *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;
+       }
+}
+
+
+/* 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_showconstantpool ******************************************************
+
+   Dump the constant pool of the given class to stdout.
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+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_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 (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_printable_ascii (cnt->name);
+                                       printf (" ");
+                                       utf_display_printable_ascii (cnt->descriptor);
+                               }
+                               break;
+                       case CONSTANT_Utf8:
+                               printf ("Utf8 -> ");
+                               utf_display_printable_ascii (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.cls) {
+               printf("Super: ");
+               utf_display_printable_ascii(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_printable_ascii(c->interfaces[i].cls->name);
+               printf (" (%d)\n", c->interfaces[i].cls->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
@@ -771,4 +1359,5 @@ s4 class_findfield_index_by_name(classinfo *c, utf *name)
  * c-basic-offset: 4
  * tab-width: 4
  * End:
+ * vim:noexpandtab:sw=4:ts=4:
  */