* src/vm/jit/s390/codegen.c (codegen_emit): Fix profiling code.
[cacao.git] / src / vm / jit / show.c
index 12d4da7d2c30d66552e704c6c9bc595c06e4ccf6..0c2d989ed9d2d0d66abd4986d8356896d610898d 100644 (file)
@@ -1,6 +1,6 @@
 /* src/vm/jit/show.c - showing the intermediate representation
 
-   Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
+   Copyright (C) 1996-2005, 2006, 2007 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
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   Contact: cacao@cacaojvm.org
-
-   Authors: Andreas Krall
-            Edwin Steiner
-            Christian Thalinger
-            Christian Ullrich
-
    $Id$
 
 */
 
 
 #include "config.h"
-#include "vm/types.h"
 
 #include <assert.h>
 
+#include "vm/types.h"
+
 #include "mm/memory.h"
 
-#if defined(ENABLE_THREADS)
-# include "threads/native/lock.h"
-#else
-# include "threads/none/lock.h"
-#endif
+#include "threads/lock-common.h"
 
 #include "vm/global.h"
-#include "vm/options.h"
 #include "vm/builtin.h"
 #include "vm/stringlocal.h"
+#include "vm/vm.h"
+
+#include "vm/jit/abi.h"
 #include "vm/jit/jit.h"
 #include "vm/jit/show.h"
 #include "vm/jit/disass.h"
 #include "vm/jit/stack.h"
 #include "vm/jit/parse.h"
 
+#include "vmcore/options.h"
+
+#if defined(ENABLE_DEBUG_FILTER)
+#      include <sys/types.h>
+#      include <regex.h>
+#      if defined(ENABLE_THREADS)
+#              include "threads/native/threads.h"
+#      else
+#              include "threads/none/threads.h"
+#      endif
+#endif
 
 /* global variables ***********************************************************/
 
@@ -86,7 +89,11 @@ bool show_init(void)
 
        show_global_lock = NEW(java_objectheader);
 
-       lock_init_object_lock(show_global_lock);
+       LOCK_INIT_OBJECT_LOCK(show_global_lock);
+#endif
+
+#if defined(ENABLE_DEBUG_FILTER)
+       show_filters_init();
 #endif
 
        /* everything's ok */
@@ -143,7 +150,7 @@ void show_method(jitdata *jd, int stage)
        s4              i, j;
        int             irstage;
 #if defined(ENABLE_DISASSEMBLER)
-       u1             *u1ptr;
+       u1             *pc;
 #endif
 
        /* get required compiler data */
@@ -345,20 +352,22 @@ void show_method(jitdata *jd, int stage)
                printf("\n");
        }
 
+#if defined(ENABLE_REPLACEMENT)
        if (code->rplpoints) {
                printf("Replacement Points:\n");
                replace_show_replacement_points(code);
                printf("\n");
        }
+#endif /* defined(ENABLE_REPLACEMENT) */
 
 #if defined(ENABLE_DISASSEMBLER)
        /* show code before first basic block */
 
        if ((stage >= SHOW_CODE) && JITDATA_HAS_FLAG_SHOWDISASSEMBLE(jd)) {
-               u1ptr = (u1 *) ((ptrint) code->mcode + cd->dseglen);
+               pc = (u1 *) ((ptrint) code->mcode + cd->dseglen);
 
-               for (; u1ptr < (u1 *) ((ptrint) code->mcode + cd->dseglen + jd->basicblocks[0].mpc);)
-                       DISASSINSTR(u1ptr);
+               for (; pc < (u1 *) ((ptrint) code->mcode + cd->dseglen + jd->basicblocks[0].mpc);)
+                       DISASSINSTR(pc);
 
                printf("\n");
        }
@@ -377,10 +386,10 @@ void show_method(jitdata *jd, int stage)
                printf("Length: %d\n\n", (s4) (code->mcodelength -
                                                                           ((ptrint) cd->dseglen + lastbptr->mpc)));
 
-               u1ptr = (u1 *) ((ptrint) code->mcode + cd->dseglen + lastbptr->mpc);
+               pc = (u1 *) ((ptrint) code->mcode + cd->dseglen + lastbptr->mpc);
 
-               for (; (ptrint) u1ptr < ((ptrint) code->mcode + code->mcodelength);)
-                       DISASSINSTR(u1ptr);
+               for (; (ptrint) pc < ((ptrint) code->mcode + code->mcodelength);)
+                       DISASSINSTR(pc);
 
                printf("\n");
        }
@@ -445,7 +454,10 @@ void show_basicblock(jitdata *jd, basicblock *bptr, int stage)
        instruction *iptr;
        int          irstage;
 #if defined(ENABLE_DISASSEMBLER)
-       u1          *u1ptr;
+       methodinfo  *m;                     /* this is only a dummy               */
+       u1          *pc;
+       s4           linenumber;
+       s4           currentlinenumber;
 #endif
 
        /* get required compiler data */
@@ -467,7 +479,10 @@ void show_basicblock(jitdata *jd, basicblock *bptr, int stage)
                }
 
                printf("======== %sL%03d ======== %s(flags: %d, bitflags: %01x, next: %d, type: ",
-                               (bptr->bitflags & BBFLAG_REPLACEMENT) ? "<REPLACE> " : "",
+#if defined(ENABLE_REPLACEMENT)
+                               (bptr->bitflags & BBFLAG_REPLACEMENT) ? "<REPLACE> " : 
+#endif
+                                                                                                               "",
                           bptr->nr, 
                           (deadcode && stage >= SHOW_STACK) ? "DEADCODE! " : "",
                           bptr->flags, bptr->bitflags, 
@@ -548,16 +563,34 @@ void show_basicblock(jitdata *jd, basicblock *bptr, int stage)
                        (!deadcode)) 
                {
                        printf("\n");
-                       u1ptr = (u1 *) (code->mcode + cd->dseglen + bptr->mpc);
+                       pc         = (u1 *) (code->mcode + cd->dseglen + bptr->mpc);
+                       linenumber = 0;
 
                        if (bptr->next != NULL) {
-                               for (; u1ptr < (u1 *) (code->mcode + cd->dseglen + bptr->next->mpc);)
-                                       DISASSINSTR(u1ptr);
+                               for (; pc < (u1 *) (code->mcode + cd->dseglen + bptr->next->mpc);) {
+                                       currentlinenumber =
+                                               dseg_get_linenumber_from_pc(&m, code->entrypoint, pc);
+
+                                       if (currentlinenumber != linenumber) {
+                                               linenumber = currentlinenumber;
+                                               printf("%4d:\n", linenumber);
+                                       }
 
-                       } 
+                                       DISASSINSTR(pc);
+                               }
+                       }
                        else {
-                               for (; u1ptr < (u1 *) (code->mcode + code->mcodelength);)
-                                       DISASSINSTR(u1ptr); 
+                               for (; pc < (u1 *) (code->mcode + code->mcodelength);) {
+                                       currentlinenumber =
+                                               dseg_get_linenumber_from_pc(&m, code->entrypoint, pc);
+
+                                       if (currentlinenumber != linenumber) {
+                                               linenumber = currentlinenumber;
+                                               printf("%4d:\n", linenumber);
+                                       }
+
+                                       DISASSINSTR(pc);
+                               }
                        }
                        printf("\n");
                }
@@ -578,14 +611,9 @@ void show_basicblock(jitdata *jd, basicblock *bptr, int stage)
 #if !defined(NDEBUG)
 
 #define SHOW_TARGET(target)                                          \
-        if (stage >= SHOW_STACK) {                                   \
+        if (stage >= SHOW_PARSE) {                                   \
             printf("--> L%03d ", (target).block->nr);                \
         }                                                            \
-        else if (stage >= SHOW_PARSE) {                              \
-            printf("--> insindex %d (L%03d) ", (target).insindex,    \
-                jd->basicblocks[jd->basicblockindex[         \
-                (target).insindex]].nr);                             \
-        }                                                            \
         else {                                                       \
             printf("--> insindex %d ", (target).insindex);           \
         }
@@ -668,7 +696,7 @@ void show_basicblock(jitdata *jd, basicblock *bptr, int stage)
         if (stage >= SHOW_PARSE) {                                   \
             putchar('"');                                            \
             utf_display_printable_ascii(                             \
-                javastring_toutf((java_lang_String *)(val), false)); \
+               javastring_toutf((java_objectheader *)(val), false)); \
             printf("\" ");                                           \
         }                                                            \
         else {                                                       \
@@ -769,11 +797,11 @@ void show_allocation(s4 type, s4 flags, s4 regoff)
                                        GET_HIGH_REG(regoff));
                else
 #  endif
-                       printf("%3s/%3s", regs[GET_LOW_REG(regoff)],
-                                       regs[GET_HIGH_REG(regoff)]);
+                       printf("%3s/%3s", abi_registers_integer_name[GET_LOW_REG(regoff)],
+                                  abi_registers_integer_name[GET_HIGH_REG(regoff)]);
 # else
                printf("%3d/%3d", GET_LOW_REG(regoff),
-                               GET_HIGH_REG(regoff));
+                          GET_HIGH_REG(regoff));
 # endif
                return;
        } 
@@ -785,7 +813,7 @@ void show_allocation(s4 type, s4 flags, s4 regoff)
                printf("%3d", regoff);
        else
 # endif
-               printf("%3s", regs[regoff]);
+               printf("%3s", abi_registers_integer_name[regoff]);
 #else
        printf("%3d", regoff);
 #endif
@@ -877,7 +905,7 @@ static void show_variable_array_intern(jitdata *jd, s4 *vars, int n, int stage,
                        if (vars[i] == UNUSED)
                                putchar('-');
                        else if (javalocals) {
-                               nr = (UNUSED - vars[i]) - 1;
+                               nr = RETADDR_FROM_JAVALOCAL(vars[i]);
                                printf("ret(L%03d)", nr);
                        }
                        else {
@@ -1180,7 +1208,7 @@ void show_icmd(jitdata *jd, instruction *iptr, bool deadcode, int stage)
                if (stage >= SHOW_STACK && iptr->sx.s23.s3.javaindex != UNUSED)
                        printf(" (javaindex %d)", iptr->sx.s23.s3.javaindex);
                if (iptr->flags.bits & INS_FLAG_RETADDR) {
-                       printf(" (retaddr L%03d)", (UNUSED - iptr->sx.s23.s2.retaddrnr) - 1);
+                       printf(" (retaddr L%03d)", RETADDR_FROM_JAVALOCAL(iptr->sx.s23.s2.retaddrnr));
                }
                break;
 
@@ -1224,6 +1252,7 @@ void show_icmd(jitdata *jd, instruction *iptr, bool deadcode, int stage)
 
        case ICMD_INLINE_START:
        case ICMD_INLINE_END:
+       case ICMD_INLINE_BODY:
 #if defined(ENABLE_INLINING)
                {
                        insinfo_inline *ii = iptr->sx.s23.s3.inlineinfo;
@@ -1294,7 +1323,6 @@ void show_icmd(jitdata *jd, instruction *iptr, bool deadcode, int stage)
                break;
 
        case ICMD_GOTO:
-       case ICMD_INLINE_GOTO:
                SHOW_TARGET(iptr->dst);
                break;
 
@@ -1365,12 +1393,7 @@ void show_icmd(jitdata *jd, instruction *iptr, bool deadcode, int stage)
                printf("high=%d low=%d count=%d\n", iptr->sx.s23.s3.tablehigh, iptr->sx.s23.s2.tablelow, i);
                while (--i >= 0) {
                        printf("\t\t%d --> ", (int) (table - iptr->dst.table));
-                       if (stage >= SHOW_STACK) {
-                               printf("L%03d\n", table->block->nr);
-                       }
-                       else {
-                               printf("insindex %d (L%03d)\n", table->insindex, BLOCK_OF(table->insindex)->nr);
-                       }
+                       printf("L%03d\n", table->block->nr);
                        table++;
                }
 
@@ -1379,24 +1402,17 @@ void show_icmd(jitdata *jd, instruction *iptr, bool deadcode, int stage)
        case ICMD_LOOKUPSWITCH:
                SHOW_S1(iptr);
 
-               printf("count=%d, default=", iptr->sx.s23.s2.lookupcount);
-               if (stage >= SHOW_STACK) {
-                       printf("L%03d\n", iptr->sx.s23.s3.lookupdefault.block->nr);
-               }
-               else {
-                       printf("insindex %d (L%03d)\n", iptr->sx.s23.s3.lookupdefault.insindex, BLOCK_OF(iptr->sx.s23.s3.lookupdefault.insindex)->nr);
-               }
+               printf("count=%d, default=L%03d\n",
+                          iptr->sx.s23.s2.lookupcount,
+                          iptr->sx.s23.s3.lookupdefault.block->nr);
 
                lookup = iptr->dst.lookup;
                i = iptr->sx.s23.s2.lookupcount;
+
                while (--i >= 0) {
-                       printf("\t\t%d --> ", lookup->value);
-                       if (stage >= SHOW_STACK) {
-                               printf("L%03d\n", lookup->target.block->nr);
-                       }
-                       else {
-                               printf("insindex %d (L%03d)\n", lookup->target.insindex, BLOCK_OF(lookup->target.insindex)->nr);
-                       }
+                       printf("\t\t%d --> L%03d\n",
+                                  lookup->value,
+                                  lookup->target.block->nr);
                        lookup++;
                }
                break;
@@ -1429,6 +1445,222 @@ void show_icmd(jitdata *jd, instruction *iptr, bool deadcode, int stage)
 }
 #endif /* !defined(NDEBUG) */
 
+/* Debug output filtering */
+
+#if defined(ENABLE_DEBUG_FILTER)
+
+#if !defined(ENABLE_THREADS)
+u2 _no_threads_filterverbosecallctr[2] = { 0, 0 };
+#endif
+
+struct show_filter {
+       /* Boolean indicating if filter is enabled. */
+       u1 enabled;
+       /* Regular expression the method name is matched against */
+       regex_t regex;
+       /* Flag set on m->filtermatches if regex matches */
+       u1 flag;
+};
+
+typedef struct show_filter show_filter_t;
+
+#define SHOW_FILTERS_SIZE 3
+
+/* Array of filters applyed on a method */
+static struct show_filter show_filters[SHOW_FILTERS_SIZE];
+
+static void show_filter_init(show_filter_t *cf, const char *str, u1 flag, u1 default_flag, const char *description) {
+       int err;
+       char err_buf[128];
+
+       if (str) {
+               err = regcomp(&cf->regex, str, REG_EXTENDED | REG_NOSUB);
+               if (err != 0) {
+                       regerror(err, &cf->regex, err_buf, sizeof(err_buf));
+                       vm_abort(
+                               "Invalid value given for %s: `%s' (%s).", 
+                               description, str, err_buf
+                       );
+               }
+               cf->flag = flag;
+               cf->enabled = 1;
+       } else {
+               cf->flag = default_flag;
+               cf->enabled = 0;
+       }
+}
+
+void show_filters_init(void) {
+
+       show_filter_init(
+               show_filters + 0,
+               opt_filter_verbosecall_include,
+               SHOW_FILTER_FLAG_VERBOSECALL_INCLUDE,
+               SHOW_FILTER_FLAG_VERBOSECALL_INCLUDE,
+               "verbose call include filter"
+       );
+
+       show_filter_init(
+               show_filters + 1,
+               opt_filter_verbosecall_exclude,
+               SHOW_FILTER_FLAG_VERBOSECALL_EXCLUDE,
+               0,
+               "verbose call exclude filter"
+       );
+
+       show_filter_init(
+               show_filters + 2,
+               opt_filter_show_method,
+               SHOW_FILTER_FLAG_SHOW_METHOD,
+               SHOW_FILTER_FLAG_SHOW_METHOD,
+               "show method filter"
+       );
+}
+
+/*
+ (Pseudo)State machine:
+
+ States are INITIAL, INCLUDE1, INCLUDE2, ..., EXCLUDE1, ..., EXCLUDE2, ...
+
+                                                        Enter              Enter
+ Enter                                                  Include            Include
+ Exclude                                                  | |                | |
+  | |    Enter              Enter              Enter      | |     Enter      | |
+  | |    Include            Include            Exclude    | |     Exclude    | |
+  | v   --------->        ---------->        ---------->  | v   ---------->  | v
+INITIAL           INCLUDE1           INCLUDE2           EXCLUDE1           EXCLUDE2
+  | ^   <---------        <----------        <----------  | ^   <----------  | ^
+  | |    Exit               Exit               Exit       | |     Exit       | |
+  | |    Include            Include            Exclude    | |     Exclude    | |
+  | |                                                     | |                | |
+ Exit                                                    Exit               Exit
+ Exclude                                                 Include            Include
+
+  Verbose call scope is active if we are in a INCLUDE state.
+
+  State encoding:
+
+  INITIAL: ctr[0] == 0, ctr[1] == 0
+  INCLUDEN: ctr[1] == N, ctr[1] == 0
+  EXCLUDEN: ctr[1] == N
+*/
+
+void show_filters_apply(methodinfo *m) {
+       int i;
+       int res;
+       char *method_name;
+       s4 len;
+       s4 dumpsize;
+
+       /* compose full name of method */
+
+       len = 
+               utf_bytes(m->class->name) +
+               1 +
+               utf_bytes(m->name) +
+               utf_bytes(m->descriptor) +
+               1;
+
+       dumpsize = dump_size(); /* allocate memory */
+
+       method_name = DMNEW(char, len);
+
+       utf_cat_classname(method_name, m->class->name);
+       strcat(method_name, ".");
+       utf_cat(method_name, m->name);
+       utf_cat(method_name, m->descriptor);
+
+       /* reset all flags */
+
+       m->filtermatches = 0;
+
+       for (i = 0; i < SHOW_FILTERS_SIZE; ++i) {
+               if (show_filters[i].enabled) {
+
+                       res = regexec(&show_filters[i].regex, method_name, 0, NULL, 0);
+
+                       if (res == 0) {
+                               m->filtermatches |= show_filters[i].flag;
+                       }
+               } else {
+                       /* Default is to show all */
+                       m->filtermatches |= show_filters[i].flag;
+               }
+       }
+
+       /* release memory */
+
+       dump_release(dumpsize); 
+
+}
+
+#define STATE_IS_INITIAL() ((FILTERVERBOSECALLCTR[0] == 0) && (FILTERVERBOSECALLCTR[1] == 0))
+#define STATE_IS_INCLUDE() ((FILTERVERBOSECALLCTR[0] > 0) && (FILTERVERBOSECALLCTR[1] == 0))
+#define STATE_IS_EXCLUDE() (FILTERVERBOSECALLCTR[1] > 0)
+#define EVENT_INCLUDE() (m->filtermatches & SHOW_FILTER_FLAG_VERBOSECALL_INCLUDE)
+#define EVENT_EXCLUDE() (m->filtermatches & SHOW_FILTER_FLAG_VERBOSECALL_EXCLUDE)
+#define TRANSITION_NEXT_INCLUDE() ++FILTERVERBOSECALLCTR[0]
+#define TRANSITION_PREV_INCLUDE() --FILTERVERBOSECALLCTR[0]
+#define TRANSITION_NEXT_EXCLUDE() ++FILTERVERBOSECALLCTR[1]
+#define TRANSITION_PREV_EXCLUDE() --FILTERVERBOSECALLCTR[1]
+
+#if 0
+void dump_state() {
+       if (STATE_IS_INITIAL()) printf("<INITIAL>\n");
+       else if (STATE_IS_INCLUDE()) printf("<INCLUDE %hd>\n", FILTERVERBOSECALLCTR[0]);
+       else if (STATE_IS_EXCLUDE()) printf("<EXCLUDE %hd>\n", FILTERVERBOSECALLCTR[1]);
+}
+#endif
+
+int show_filters_test_verbosecall_enter(methodinfo *m) {
+
+       int force_show = 0;
+
+       if (STATE_IS_INITIAL()) {
+               if (EVENT_INCLUDE()) {
+                       TRANSITION_NEXT_INCLUDE();
+               }
+       } else if (STATE_IS_INCLUDE()) {
+               if (EVENT_EXCLUDE()) {
+                       TRANSITION_NEXT_EXCLUDE();
+                       /* just entered exclude, show this method */
+                       force_show = 1;
+               } else if (EVENT_INCLUDE()) {
+                       TRANSITION_NEXT_INCLUDE();
+               }
+       } else if (STATE_IS_EXCLUDE()) {
+               if (EVENT_EXCLUDE()) {
+                       TRANSITION_NEXT_EXCLUDE();
+               }
+       }
+
+       return STATE_IS_INCLUDE() || force_show;
+}
+
+int show_filters_test_verbosecall_exit(methodinfo *m) {
+
+       int force_show = 0;
+
+       if (m) {
+               if (STATE_IS_INCLUDE()) {
+                       if (EVENT_INCLUDE()) {
+                               TRANSITION_PREV_INCLUDE();
+                               /* just entered initial, show this method */
+                               if (STATE_IS_INITIAL()) force_show = 1;
+                       }
+           } else if (STATE_IS_EXCLUDE()) {
+                       if (EVENT_EXCLUDE()) {
+                               TRANSITION_PREV_EXCLUDE();
+                       }
+               }
+       }
+
+       return STATE_IS_INCLUDE() || force_show;
+}
+
+#endif
+
 
 /*
  * These are local overrides for various environment variables in Emacs.