* src/vm/options.h, src/vm/method.c, src/vm/jit/inline/inline.c,
[cacao.git] / src / vm / method.c
index 80f481edd11c77bf95b7c35c03c5a66df950b847..58e0da3b84a8ce68a4a88ab5b12650ee9dc80604 100644 (file)
@@ -1,9 +1,9 @@
 /* src/vm/method.c - method 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
 
             Edwin Steiner
             Christian Thalinger
 
-   $Id: method.c 3412 2005-10-12 12:54:02Z twisti $
+   $Id: method.c 7228 2007-01-19 01:13:48Z edwin $
 
 */
 
 
-#include "vm/global.h"
+#include "config.h"
+
+#include <assert.h>
+#include <stdio.h>
+
+#include "vm/types.h"
+
 #include "mm/memory.h"
-#include "vm/method.h"
 #include "vm/class.h"
+#include "vm/global.h"
+#include "vm/linker.h"
 #include "vm/loader.h"
-#include "vm/jit/codegen.inc.h"
+#include "vm/method.h"
+#include "vm/options.h"
+#include "vm/jit/methodheader.h"
+
+
+#if !defined(NDEBUG) && defined(ENABLE_INLINING)
+#define INLINELOG(code)  do { if (opt_inline_debug_log) { code } } while (0)
+#else
+#define INLINELOG(code)
+#endif
 
 
 /* method_free *****************************************************************
@@ -56,11 +72,10 @@ void method_free(methodinfo *m)
        if (m->jcode)
                MFREE(m->jcode, u1, m->jcodelength);
 
-       if (m->exceptiontable)
-               MFREE(m->exceptiontable, exceptiontable, m->exceptiontablelength);
+       if (m->rawexceptiontable)
+               MFREE(m->rawexceptiontable, raw_exception_entry, m->rawexceptiontablelength);
 
-       if (m->mcode)
-               CFREE((void *) (ptrint) m->mcode, m->mcodelength);
+       code_free_code_of_method(m);
 
        if (m->stubroutine) {
                if (m->flags & ACC_NATIVE) {
@@ -94,89 +109,304 @@ bool method_canoverwrite(methodinfo *m, methodinfo *old)
        return true;
 }
 
-/* method_descriptor2types *****************************************************
 
-   Fills in the following members of the given methodinfo:
-       returntype
-          paramcount
-       paramtypes         
+/* method_vftbl_lookup *********************************************************
 
-   Note:
-       This function uses dump_alloc functions to allocate memory.
+   Does a method lookup in the passed virtual function table.  This
+   function does exactly the same thing as JIT, but additionally
+   relies on the fact, that the methodinfo pointer is at the first
+   data segment slot (even for compiler stubs).
 
-*******************************************************************************/               
+*******************************************************************************/
 
-void method_descriptor2types(methodinfo *m)
+methodinfo *method_vftbl_lookup(vftbl_t *vftbl, methodinfo* m)
 {
-       u1 *types, *tptr;
-       int pcount, i;
-       methoddesc *md = m->parseddesc;
-       typedesc *paramtype;
-       
-       pcount = md->paramcount;
-       if ((m->flags & ACC_STATIC) == 0)
-               pcount++; /* count this pointer */
-       
-       types = DMNEW(u1,pcount);
-       tptr = types;
-       
-       if (!(m->flags & ACC_STATIC)) {
-               /* this pointer */
-               *tptr++ = TYPE_ADR;
+       methodptr   mptr;
+       methodptr  *pmptr;
+       methodinfo *resm;                   /* pointer to new resolved method     */
+       codeinfo   *code;
+
+       /* If the method is not an instance method, just return it. */
+
+       if (m->flags & ACC_STATIC)
+               return m;
+
+       assert(vftbl);
+
+       /* Get the method from the virtual function table.  Is this an
+          interface method? */
+
+       if (m->class->flags & ACC_INTERFACE) {
+               pmptr = vftbl->interfacetable[-(m->class->index)];
+               mptr  = pmptr[(m - m->class->methods)];
+       }
+       else {
+               mptr = vftbl->table[m->vftblindex];
+       }
+
+       /* and now get the codeinfo pointer from the first data segment slot */
+
+       code = *((codeinfo **) (mptr + CodeinfoPointer));
+
+       resm = code->m;
+
+       return resm;
+}
+
+
+/* method_count_implementations ************************************************
+
+   Count the implementations of a method in a class cone (a class and all its
+   subclasses.)
+
+   IN:
+       m................the method to count
+          c................class at which to start the counting (this class and
+                           all its subclasses will be searched)
+
+   OUT:
+       *found...........if found != NULL, *found receives the method
+                           implementation that was found. This value is only
+                                               meaningful if the return value is 1.
+
+   RETURN VALUE:
+       the number of implementations found
+
+*******************************************************************************/
+
+s4 method_count_implementations(methodinfo *m, classinfo *c, methodinfo **found)
+{
+       s4          count;
+       methodinfo *mp;
+       methodinfo *mend;
+       classinfo  *child;
+
+       count = 0;
+
+       mp = c->methods;
+       mend = mp + c->methodscount;
+
+       for (; mp < mend; ++mp) {
+               if (method_canoverwrite(mp, m)) {
+                       if (found)
+                               *found = mp;
+                       count++;
+                       break;
+               }
+       }
+
+       for (child = c->sub; child != NULL; child = child->nextsub) {
+               count += method_count_implementations(m, child, found);
+       }
+
+       return count;
+}
+
+
+/* method_add_to_worklist ******************************************************
+
+   Add the method to the given worklist. If the method already occurs in
+   the worklist, the worklist remains unchanged.
+
+*******************************************************************************/
+
+static void method_add_to_worklist(methodinfo *m, method_worklist **wl)
+{
+       method_worklist *wi;
+
+       for (wi = *wl; wi != NULL; wi = wi->next)
+               if (wi->m == m)
+                       return;
+
+       wi = NEW(method_worklist);
+       wi->next = *wl;
+       wi->m = m;
+
+       *wl = wi;
+}
+
+
+/* method_add_assumption_monomorphic *******************************************
+
+   Record the assumption that the method is monomorphic.
+
+   IN:
+      m.................the method
+         caller............the caller making the assumption
+
+*******************************************************************************/
+
+void method_add_assumption_monomorphic(methodinfo *m, methodinfo *caller)
+{
+       method_assumption *as;
+
+       /* XXX LOCKING FOR THIS FUNCTION? */
+
+       /* check if we already have registered this assumption */
+
+       for (as = m->assumptions; as != NULL; as = as->next) {
+               if (as->context == caller)
+                       return;
        }
 
-       paramtype = md->paramtypes;
-       for (i=0; i<md->paramcount; ++i,++paramtype)
-               *tptr++ = paramtype->type;
+       /* register the assumption */
+
+       as = NEW(method_assumption);
+       as->next = m->assumptions;
+       as->context = caller;
+
+       m->assumptions = as;
+}
+
+
+/* method_break_assumption_monomorphic *****************************************
+
+   Break the assumption that this method is monomorphic. All callers that
+   have registered this assumption are added to the worklist.
+
+   IN:
+      m.................the method
+         wl................worklist where to add invalidated callers
+
+*******************************************************************************/
+
+void method_break_assumption_monomorphic(methodinfo *m, method_worklist **wl)
+{
+       method_assumption *as;
+
+       /* XXX LOCKING FOR THIS FUNCTION? */
 
-       m->returntype = md->returntype.type;
-       m->paramcount = pcount;
-       m->paramtypes = types;
+       for (as = m->assumptions; as != NULL; as = as->next) {
+               INLINELOG(
+                       printf("ASSUMPTION BROKEN (monomorphism): ");
+                       method_print(m);
+                       printf(" in ");
+                       method_println(as->context);
+               );
+
+               method_add_to_worklist(as->context, wl);
+       }
 }
 
-/************** Function: method_display  (debugging only) **************/
 
-void method_display(methodinfo *m)
+/* method_printflags ***********************************************************
+
+   Prints the flags of a method to stdout like.
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+void method_printflags(methodinfo *m)
 {
-       printf("   ");
-       printflags(m->flags);
-       printf(" ");
-       utf_display(m->name);
-       printf(" "); 
-       utf_display(m->descriptor);
+       if (m == NULL) {
+               printf("NULL");
+               return;
+       }
+
+       if (m->flags & ACC_PUBLIC)       printf(" PUBLIC");
+       if (m->flags & ACC_PRIVATE)      printf(" PRIVATE");
+       if (m->flags & ACC_PROTECTED)    printf(" PROTECTED");
+       if (m->flags & ACC_STATIC)       printf(" STATIC");
+       if (m->flags & ACC_FINAL)        printf(" FINAL");
+       if (m->flags & ACC_SYNCHRONIZED) printf(" SYNCHRONIZED");
+       if (m->flags & ACC_VOLATILE)     printf(" VOLATILE");
+       if (m->flags & ACC_TRANSIENT)    printf(" TRANSIENT");
+       if (m->flags & ACC_NATIVE)       printf(" NATIVE");
+       if (m->flags & ACC_INTERFACE)    printf(" INTERFACE");
+       if (m->flags & ACC_ABSTRACT)     printf(" ABSTRACT");
+       if (m->flags & ACC_METHOD_MONOMORPHIC) printf(" (mono)");
+       if (m->flags & ACC_METHOD_IMPLEMENTED) printf(" (impl)");
+}
+#endif /* !defined(NDEBUG) */
+
+
+/* method_print ****************************************************************
+
+   Prints a method to stdout like:
+
+   java.lang.Object.<init>()V
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+void method_print(methodinfo *m)
+{
+       if (m == NULL) {
+               printf("NULL");
+               return;
+       }
+
+       utf_display_printable_ascii_classname(m->class->name);
+       printf(".");
+       utf_display_printable_ascii(m->name);
+       utf_display_printable_ascii(m->descriptor);
+
+       method_printflags(m);
+}
+#endif /* !defined(NDEBUG) */
+
+
+/* method_println **************************************************************
+
+   Prints a method plus new line to stdout like:
+
+   java.lang.Object.<init>()V
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+void method_println(methodinfo *m)
+{
+       if (opt_debugcolor) printf("\033[31m"); /* red */
+       method_print(m);
+       if (opt_debugcolor) printf("\033[m");   
        printf("\n");
 }
+#endif /* !defined(NDEBUG) */
+
 
-/************** Function: method_display_w_class  (debugging only) **************/
+/* method_methodref_print ******************************************************
 
-void method_display_w_class(methodinfo *m)
+   Prints a method reference to stdout.
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+void method_methodref_print(constant_FMIref *mr)
 {
-        printflags(m->class->flags);
-        printf(" "); fflush(stdout);
-        utf_display(m->class->name);
-        printf(".");fflush(stdout);
-
-        printf("   ");
-        printflags(m->flags);
-        printf(" "); fflush(stdout);
-        utf_display(m->name);
-        printf(" "); fflush(stdout);
-        utf_display(m->descriptor);
-        printf("\n"); fflush(stdout);
+       if (!mr) {
+               printf("(constant_FMIref *)NULL");
+               return;
+       }
+
+       if (IS_FMIREF_RESOLVED(mr)) {
+               printf("<method> ");
+               method_print(mr->p.method);
+       }
+       else {
+               printf("<methodref> ");
+               utf_display_printable_ascii_classname(mr->p.classref->name);
+               printf(".");
+               utf_display_printable_ascii(mr->name);
+               utf_display_printable_ascii(mr->descriptor);
+       }
 }
+#endif /* !defined(NDEBUG) */
+
+
+/* method_methodref_println ****************************************************
 
-/************** Function: method_display_flags_last  (debugging only) **************/
+   Prints a method reference to stdout, followed by a newline.
 
-void method_display_flags_last(methodinfo *m)
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+void method_methodref_println(constant_FMIref *mr)
 {
-        printf(" ");
-        utf_display(m->name);
-        printf(" ");
-        utf_display(m->descriptor);
-        printf("   ");
-        printflags(m->flags);
-        printf("\n");
+       method_methodref_print(mr);
+       printf("\n");
 }
+#endif /* !defined(NDEBUG) */
 
 
 /*
@@ -190,4 +420,5 @@ void method_display_flags_last(methodinfo *m)
  * c-basic-offset: 4
  * tab-width: 4
  * End:
+ * vim:noexpandtab:sw=4:ts=4:
  */