Merged.
[cacao.git] / src / vm / jit / optimizing / escape.c
index 71cf200fb4a128fede8e443f2cbdb998ea4eb579..329ba02f066e6bd6f8b1971c0771483a9d3c950a 100644 (file)
@@ -1,7 +1,89 @@
-#include "vm/jit/jit.h"
-#include "vmcore/class.h"
+/* src/vm/jit/optimizing/escape.c
+
+   Copyright (C) 2008
+   CACAOVM - Verein zu Foerderung der freien virtuellen Machine CACAO
+
+   This file is part of CACAO.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+*/
+
+
+#include "config.h"
+
+#include "vm/class.hpp"
+#include "vm/classcache.hpp"
+
+#include "vm/jit/jit.hpp"
 #include "vm/jit/optimizing/escape.h"
 
+#include <stdarg.h>
+
+#if defined(ENABLE_ESCAPE_REASON)
+#define ENABLE_REASON
+#endif
+
+#if defined(ENABLE_REASON)
+#define I2(why, tov, es) escape_analysis_record_reason(e, why, iptr, tov, es);
+#else
+#define I2(why, tov, es)
+#endif
+#define I(why, to, from) I2(why, instruction_ ## to (iptr), escape_analysis_get_state(e, instruction_ ## from (iptr)))
+#define E2(why, var) I2(why, var, ESCAPE_GLOBAL)
+#define E(why, which) E2(why, instruction_ ## which (iptr))
+
+typedef enum {
+       RED = 31,
+       GREEN,
+       YELLOW,
+       BLUE,
+       MAGENTA,
+       CYAN,
+       WHITE,
+       COLOR_END
+} color_t;
+
+#define ENABLE_COLOR
+
+static void color_start(color_t color) {
+#if defined(ENABLE_COLOR)
+       if (RED <= color && color < COLOR_END) {
+               printf("\033[%dm", color);
+       }
+#endif
+}
+
+static void color_end() {
+#if defined(ENABLE_COLOR)
+       printf("\033[m");
+       fflush(stdout);
+#endif
+}
+
+static void color_printf(color_t color, const char *fmt, ...) {
+       va_list ap;
+       color_start(color);
+       va_start(ap, fmt);
+       vprintf(fmt, ap);
+       va_end(ap);
+       color_end();
+}
+
+
 /*** escape_state *************************************************************/
 
 const char *escape_state_to_string(escape_state_t escape_state) {
@@ -10,7 +92,7 @@ const char *escape_state_to_string(escape_state_t escape_state) {
                str(ESCAPE_UNKNOWN)
                str(ESCAPE_NONE)
                str(ESCAPE_METHOD)
-               str(ESCAPE_GLOBAL_THROUGH_METHOD)
+               str(ESCAPE_METHOD_RETURN)
                str(ESCAPE_GLOBAL)
                default: return "???";
        }
@@ -127,6 +209,8 @@ typedef struct {
 
        instruction_list_t *allocations;
        instruction_list_t *getfields;
+       instruction_list_t *monitors;
+       instruction_list_t *returns;
 
        struct var_extra **var;
 
@@ -251,12 +335,25 @@ void dependenCy_list_import(dependency_list_t *dl, dependency_list_t *other) {
 
 /*** var_extra ***************************************************************/
 
+#if defined(ENABLE_REASON)
+typedef struct reason {
+       const char *why;
+       instruction *iptr;
+       struct reason *next;
+} reason_t;
+#endif
+
 typedef struct var_extra {
        instruction *allocation;
        escape_state_t escape_state;
        s4 representant;
        dependency_list_t *dependency_list;
-       bool is_arg; /* TODO optimize */
+       unsigned contains_arg:1;
+       unsigned contains_only_args:1;
+       /*signed adr_arg_num:30;*/
+#if defined(ENABLE_REASON)
+       reason_t *reasons;
+#endif
 } var_extra_t;
 
 static void var_extra_init(var_extra_t *ve) {
@@ -264,7 +361,12 @@ static void var_extra_init(var_extra_t *ve) {
        ve->escape_state = ESCAPE_NONE;
        ve->representant = -1;
        ve->dependency_list = NULL;
-       ve->is_arg = false;
+       ve->contains_arg = false;
+       ve->contains_only_args = false;
+       /*ve->adr_arg_num = -1;*/
+#if defined(ENABLE_REASON)
+       ve->reasons = NULL;
+#endif
 }
 
 static inline var_extra_t *var_extra_get_no_alloc(const escape_analysis_t *e, s4 var) {
@@ -348,18 +450,41 @@ static void escape_analysis_init(escape_analysis_t *e, jitdata *jd) {
        e->getfields = DNEW(instruction_list_t);
        instruction_list_init(e->getfields);
 
+       e->monitors = DNEW(instruction_list_t);
+       instruction_list_init(e->monitors);
+
+       e->returns = DNEW(instruction_list_t);
+       instruction_list_init(e->returns);
+
        e->var = DMNEW(var_extra_t *, jd->vartop);
        MZERO(e->var, var_extra_t *, jd->vartop);
 
        e->adr_args_count = 0;
 
-       e->verbose = (
-               strcmp(e->jd->m->clazz->name->text, "gnu/java/util/regex/RESyntax") == 0 
-               && strcmp(e->jd->m->name->text, "<clinit>") == 0
-       );
        e->verbose = 1;
+       e->verbose = strcmp(jd->m->name->text, "<init>") == 0;
+       e->verbose = getenv("EV") != NULL;
 }
 
+#if defined(ENABLE_REASON)
+static void escape_analysis_record_reason(escape_analysis_t *e, const char *why, instruction *iptr, s4 var, escape_state_t es) {
+       var_extra_t *ve;
+       reason_t *re;
+       if (es == ESCAPE_GLOBAL || es == ESCAPE_METHOD_RETURN) {
+               var = var_extra_get_representant(e, var);
+               ve = var_extra_get(e, var);
+               re = NEW(reason_t);
+               re->why = why;
+               re->iptr= iptr;
+               re->next = ve->reasons;
+               ve->reasons = re;
+               if (e->verbose) {
+                       printf("%d escapes because %s\n", var, why);
+               }
+       }
+}
+#endif
+
 static void escape_analysis_set_allocation(escape_analysis_t *e, s4 var, instruction *iptr) {
        var_extra_get(e, var)->allocation = iptr;
 }
@@ -373,12 +498,38 @@ static instruction *escape_analysis_get_allocation(const escape_analysis_t *e, s
        return ve->allocation;
 }
 
-static void escape_analysis_set_is_argument(escape_analysis_t *e, s4 var) {
-       var_extra_get(e, var)->is_arg = true;
+static void escape_analysis_set_contains_argument(escape_analysis_t *e, s4 var) {
+       var = var_extra_get_representant(e, var);
+       var_extra_get(e, var)->contains_arg = true;
+}
+
+static bool escape_analysis_get_contains_argument(escape_analysis_t *e, s4 var) {
+       var = var_extra_get_representant(e, var);
+       return var_extra_get(e, var)->contains_arg;
+}
+
+static void escape_analysis_set_contains_only_arguments(escape_analysis_t *e, s4 var) {
+       var = var_extra_get_representant(e, var);
+       var_extra_get(e, var)->contains_only_args = true;
+}
+
+static bool escape_analysis_get_contains_only_arguments(escape_analysis_t *e, s4 var) {
+       var = var_extra_get_representant(e, var);
+       return var_extra_get(e, var)->contains_only_args;
 }
 
-static bool escape_analysis_get_is_argument(escape_analysis_t *e, s4 var) {
-       return var_extra_get(e, var)->is_arg;
+/*
+static void escape_analysis_set_adr_arg_num(escape_analysis_t *e, s4 var, s4 num) {
+       var_extra_get(e, var)->adr_arg_num = num;
+}
+
+static s4 escape_analysis_get_adr_arg_num(escape_analysis_t *e, s4 var) {
+       return var_extra_get(e, var)->adr_arg_num;
+}
+*/
+
+static bool escape_analysis_in_same_set(escape_analysis_t *e, s4 var1, s4 var2) {
+       return var_extra_get_representant(e, var1) == var_extra_get_representant(e, var2);
 }
 
 static void escape_analysis_ensure_state(escape_analysis_t *e, s4 var, escape_state_t escape_state) {
@@ -409,6 +560,10 @@ static void escape_analysis_ensure_state(escape_analysis_t *e, s4 var, escape_st
                                        dependency_list_item_get_dependency(it),
                                        escape_state
                                );
+                               {
+                               instruction *iptr = NULL;
+                               I2("propagated by dependency", dependency_list_item_get_dependency(it), escape_state);
+                               }
                        }
                }
        }
@@ -418,12 +573,6 @@ static escape_state_t escape_analysis_get_state(escape_analysis_t *e, s4 var) {
        return var_extra_get_escape_state(e, var);
 }
 
-#define escape_analysis_assert_has_escape(e, var) \
-       assert( \
-               var_extra_get_no_alloc(e, var) && \
-               (var_extra_get_no_alloc(e, var)->escape_state > ESCAPE_UNKNOWN) \
-       )
-
 static classinfo *escape_analysis_classinfo_in_var(escape_analysis_t *e, s4 var) {
        instruction *iptr = escape_analysis_get_allocation(e, var);
 
@@ -461,6 +610,8 @@ static void escape_analysis_merge(escape_analysis_t *e, s4 var1, s4 var2) {
                return;
        }
 
+       if (e->verbose) printf("Merging (%d,%d)\n", var1, var2);
+
        ve1 = var_extra_get(e, var1);
        ve2 = var_extra_get(e, var2);
 
@@ -473,10 +624,10 @@ static void escape_analysis_merge(escape_analysis_t *e, s4 var1, s4 var2) {
 
        ve2->representant = var1;
 
-       /* Adjust is_argument to logical or. */
+       /* Adjust is_arg to logical or. */
        
-       has_become_arg = ve1->is_arg != ve2->is_arg;
-       ve1->is_arg = ve1->is_arg || ve2->is_arg;
+       has_become_arg = ve1->contains_arg != ve2->contains_arg;
+       ve1->contains_arg = ve1->contains_arg || ve2->contains_arg;
 
        if (e->verbose && has_become_arg) printf("(%d,%d) has become arg.\n", var1, var2);
 
@@ -498,8 +649,35 @@ static void escape_analysis_merge(escape_analysis_t *e, s4 var1, s4 var2) {
                                dependency_list_item_get_dependency(itd),
                                ESCAPE_GLOBAL
                        );
+                       {
+                       instruction *iptr = NULL;
+                       E2("has become arg", dependency_list_item_get_dependency(itd));
+                       }
                }
        }
+
+       /* Adjust contains_only_args to logical and. */
+
+       ve1->contains_only_args = ve1->contains_only_args && ve2->contains_only_args;
+
+       /* Adjust address argument number contained in this var. */
+
+       /*
+       if (ve1->adr_arg_num != ve2->adr_arg_num) {
+               ve1->adr_arg_num = -1;
+       }
+       */
+#if defined(ENABLE_REASON)
+       if (ve1->reasons) {
+               reason_t *re = ve1->reasons;
+               while (re->next != NULL) {
+                       re = re->next;
+               }
+               re->next = ve2->reasons;
+       } else {
+               ve1->reasons = ve2->reasons;
+       }
+#endif
 }
 
 static void escape_analysis_add_dependency(escape_analysis_t *e, instruction *store) {
@@ -511,7 +689,9 @@ static void escape_analysis_add_dependency(escape_analysis_t *e, instruction *st
        dependency_list_add(dl, store);
 
        if (e->verbose) {
-               printf("dependency_list_add\n");
+               printf("dependency_list_add: %d.dependency_list.add( { ", obj);
+               show_icmd(e->jd, store, 0, 3);
+               printf(" } )\n"); 
        }
 }
 
@@ -522,12 +702,16 @@ static void escape_analysis_process_instruction(escape_analysis_t *e, instructio
        u1 *paramescape;
        unsigned i;
        instruction **iarg;
-       constant_FMIref *fmi;
        methodinfo *mi;
-       resolve_result_t result;
+       escape_state_t es;
+       const char *why;
 
        if (e->verbose) {
-               printf("processing %s@%d\n", icmd_table[iptr->opc].name, iptr->line);
+               color_start(CYAN);
+               printf("%d: ", iptr->line);
+               show_icmd(e->jd, iptr, 0, 3);
+               color_end();
+               printf("\n");
        }
 
        switch (instruction_get_opcode(iptr)) {
@@ -545,46 +729,51 @@ static void escape_analysis_process_instruction(escape_analysis_t *e, instructio
 
                        if (c == NULL) {
                                escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
-                               if (e->verbose) printf("1\n");
+                               E("unresolved class", dst)
                        } else if (c->finalizer != NULL) {
                                escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
-                               if (e->verbose) printf("3\n");
+                               E("finalizer", dst)
                        } else {
                                escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
-                               if (e->verbose) printf("2\n");
                        }
 
                        instruction_list_add(e->allocations, iptr);
 
                        break;
 
+               case ICMD_MONITORENTER:
+               case ICMD_MONITOREXIT:
+               
+                       instruction_list_add(e->monitors, iptr);
+
+                       break;
+
                case ICMD_NEWARRAY:
                case ICMD_ANEWARRAY:
                        
                        escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
                        escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
                        instruction_list_add(e->allocations, iptr);
-
+                       E("untracked array", dst)
                        break;
 
                case ICMD_PUTSTATIC:
                        if (instruction_field_type(iptr) == TYPE_ADR) {
-                               /*
-                               escape_analysis_assert_has_escape(e, instruction_s1(iptr));
-                               */
                                escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_GLOBAL);
+                               E("putstatic", s1)
                        }
                        break;
 
                case ICMD_PUTFIELD:
                        if (instruction_field_type(iptr) == TYPE_ADR) {
-                               /*
-                               escape_analysis_assert_has_escape(e, instruction_s1(iptr));
-                               escape_analysis_assert_has_escape(e, instruction_s2(iptr));
-                               */
-                               if (escape_analysis_get_is_argument(e, instruction_s1(iptr))) {
+                               if (escape_analysis_get_contains_argument(e, instruction_s1(iptr))) {
                                        escape_analysis_ensure_state(e, instruction_s2(iptr), ESCAPE_GLOBAL);
+                                       /* If s1 is currently not an argument, but can contain one later because
+                                          of a phi function, the merge function takes care to make all
+                                          dependencies escape globally. */
+                                       E("putfield into argument", s2)
                                } else {
+                                       I("putfield inherit", s2, s1);
                                        escape_analysis_ensure_state(e, instruction_s2(iptr), escape_analysis_get_state(e, instruction_s1(iptr)));
                                        escape_analysis_add_dependency(e, iptr);
                                }
@@ -592,13 +781,13 @@ static void escape_analysis_process_instruction(escape_analysis_t *e, instructio
                        break;
 
                case ICMD_AASTORE:
-                       /*
-                       escape_analysis_assert_has_escape(e, instruction_s1(iptr));
-                       escape_analysis_assert_has_escape(e, instruction_s3(iptr));
-                       */
-                       if (escape_analysis_get_is_argument(e, instruction_s1(iptr))) {
+                       if (escape_analysis_get_contains_argument(e, instruction_s1(iptr))) {
+                               if (e->verbose) printf("Contains argument.\n");
                                escape_analysis_ensure_state(e, instruction_s3(iptr), ESCAPE_GLOBAL);
+                               E("aastore into argument", s3)
                        } else {
+                               if (e->verbose) printf("Contains no argument.\n");
+                               I("aastore", s3, s1)
                                escape_analysis_ensure_state(e, instruction_s3(iptr), escape_analysis_get_state(e, instruction_s1(iptr)));
                                escape_analysis_add_dependency(e, iptr);
                        }
@@ -607,22 +796,21 @@ static void escape_analysis_process_instruction(escape_analysis_t *e, instructio
                case ICMD_GETSTATIC:
                        if (instruction_field_type(iptr) == TYPE_ADR) {
                                escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
+                               E("loaded from static var", dst)
                                escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
                        }
                        break;
 
                case ICMD_GETFIELD:
                        if (instruction_field_type(iptr) == TYPE_ADR) {
-                               /*
-                               escape_analysis_assert_has_escape(e, instruction_s1(iptr));
-                               */
 
-                               if (escape_analysis_get_is_argument(e, instruction_s1(iptr))) {
+                               if (escape_analysis_get_contains_argument(e, instruction_s1(iptr))) {
                                        /* Fields loaded from arguments escape globally.
                                           x = arg.foo;
                                           x.bar = y;
                                           => y escapes globally. */
                                        escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
+                                       E("loaded from arg", dst)
                                } else {
                                        escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
                                }
@@ -634,19 +822,15 @@ static void escape_analysis_process_instruction(escape_analysis_t *e, instructio
                        break;
 
                case ICMD_ARRAYLENGTH:
-                       /*
-                       escape_analysis_assert_has_escape(e, instruction_s1(iptr));
-                       */
+                       escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
                        break;
 
                case ICMD_AALOAD:
-                       /*
-                       escape_analysis_assert_has_escape(e, instruction_s1(iptr));
-                       */
 
-                       if (escape_analysis_get_is_argument(e, instruction_s1(iptr))) {
+                       if (escape_analysis_get_contains_argument(e, instruction_s1(iptr))) {
                                /* If store into argument, escapes globally. See ICMD_GETFIELD. */
                                escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
+                               E("aaload from argument", dst)
                        } else {
                                escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
                        }
@@ -658,36 +842,27 @@ static void escape_analysis_process_instruction(escape_analysis_t *e, instructio
 
                case ICMD_IF_ACMPEQ:
                case ICMD_IF_ACMPNE:
-                       /*
-                       escape_analysis_assert_has_escape(e, instruction_s1(iptr));
-                       escape_analysis_assert_has_escape(e, instruction_s2(iptr));
-                       */
                        escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
                        escape_analysis_ensure_state(e, instruction_s2(iptr), ESCAPE_METHOD);
                        break;
 
                case ICMD_IFNULL:
                case ICMD_IFNONNULL:
+                       escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
+                       break;
+
                case ICMD_CHECKNULL:
-                       /*
-                       escape_analysis_assert_has_escape(e, instruction_s1(iptr));
-                       */
                        escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
+                       escape_analysis_merge(e, instruction_s1(iptr), instruction_dst(iptr));
                        break;
 
                case ICMD_CHECKCAST:
-                       /*
-                       escape_analysis_assert_has_escape(e, instruction_s1(iptr));
-                       */
                        escape_analysis_merge(e, instruction_s1(iptr), instruction_dst(iptr));
                        escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
                        escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
                        break;
 
                case ICMD_INSTANCEOF:
-                       /*
-                       escape_analysis_assert_has_escape(e, instruction_s1(iptr));
-                       */
                        escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
                        break;
 
@@ -698,15 +873,25 @@ static void escape_analysis_process_instruction(escape_analysis_t *e, instructio
                        count = instruction_arg_count(iptr);
                        mi = instruction_local_methodinfo(iptr);
                        paramescape = NULL;
+                       why = "???";
 
                        if (mi != NULL) {
                                /* If the method could be resolved, it already is. */
                                paramescape = mi->paramescape;
 
+                               if (e->verbose) {
+                                       if (paramescape) {
+                                               printf("Paramescape for callee available.\n");
+                                       }
+                               }
+
+                               if (paramescape) why = "Available param escape";
+
                                if (paramescape == NULL) {
                                        if (e->verbose) {
                                                printf("BC escape analyzing callee.\n");
                                        }
+                                       why = "BC param escape";
                                        bc_escape_analysis_perform(mi);
                                        paramescape = mi->paramescape;
                                }
@@ -714,26 +899,66 @@ static void escape_analysis_process_instruction(escape_analysis_t *e, instructio
                                if (e->verbose) {
                                        printf("Unresolved callee.\n");
                                }
+                               why = "Unresolved callee";
+                       }
+
+                       if (iptr->opc == ICMD_INVOKEVIRTUAL || iptr->opc == ICMD_INVOKEINTERFACE) {
+                               if (mi != NULL && !escape_is_monomorphic(e->jd->m, mi)) {
+                                       if (e->verbose) {
+                                               printf("Not monomorphic.\n");
+                                       }
+                                       why = "Polymorphic";
+                                       paramescape = NULL;
+                               }
                        }
 
+                       /* Set the escape state of the return value.
+                          This is: global if we down have information of the callee, or the callee
+                          supplied escape state. */
+
+                       if (instruction_return_type(iptr) == TYPE_ADR) {
+                               if (paramescape == NULL) {
+                                       escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
+                                       E(why, dst);
+                               } else {
+                                       es = escape_state_from_u1(paramescape[-1]);
+                                       I2(why, instruction_dst(iptr), es)
+                                       escape_analysis_ensure_state(e, instruction_dst(iptr), es);
+                               }
+                               escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
+                       }
+                       
                        for (i = 0; i < count; ++i) {
                                if (instruction_arg_type(iptr, i) == TYPE_ADR) {
 
-                                       /*
-                                       escape_analysis_assert_has_escape(e, instruction_arg(iptr, i));
-                                       */
                                        if (paramescape == NULL) {
                                                escape_analysis_ensure_state(
                                                        e, 
                                                        instruction_arg(iptr, i), 
-                                                       instruction_local_methodinfo(iptr) && instruction_local_methodinfo(iptr)->jcode ?
-                                                               ESCAPE_GLOBAL_THROUGH_METHOD :
-                                                               ESCAPE_GLOBAL
+                                                       ESCAPE_GLOBAL
                                                );
-                                       } else if ((escape_state_t)*paramescape < ESCAPE_METHOD) {
-                                               escape_analysis_ensure_state(e, instruction_arg(iptr, i), ESCAPE_METHOD);
+                                               E2(why, instruction_arg(iptr, i));
+                                       } else if (escape_state_from_u1(*paramescape) <= ESCAPE_METHOD) {
+                                               es = escape_state_from_u1(*paramescape);
+
+                                               if (es < ESCAPE_METHOD) {
+                                                       es = ESCAPE_METHOD;
+                                               }
+
+                                               I2(why, instruction_arg(iptr, i), es);
+                                               escape_analysis_ensure_state(e, instruction_arg(iptr, i), es);
+
+                                               if (*paramescape & 0x80) {
+                                                       /* Parameter can be returned from method.
+                                                          This creates an alias to the retur value.
+                                                          If the return value escapes, the ES of the parameter needs 
+                                                          to be adjusted. */
+                                                       escape_analysis_merge(e, instruction_arg(iptr, i), instruction_dst(iptr));
+                                                       I2("return alias", instruction_arg(iptr, i), instruction_dst(iptr));
+                                               }
                                        } else {
-                                               escape_analysis_ensure_state(e, instruction_arg(iptr, i), (escape_state_t)*paramescape);
+                                               escape_analysis_ensure_state(e, instruction_arg(iptr, i), ESCAPE_GLOBAL);
+                                               E2(why, instruction_arg(iptr, i));
                                        }
 
                                        if (paramescape != NULL) {
@@ -742,25 +967,20 @@ static void escape_analysis_process_instruction(escape_analysis_t *e, instructio
                                }
                        }
 
-                       if (instruction_return_type(iptr) == TYPE_ADR) {
-                               escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
-                               escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
-                       }
-
                        break;
 
                case ICMD_ATHROW:
-                       /*
-                       escape_analysis_assert_has_escape(e, instruction_s1(iptr));
-                       */
                        escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_GLOBAL);
+                       E("throw", s1)
                        break;
 
                case ICMD_ARETURN:
-                       /*
-                       escape_analysis_assert_has_escape(e, instruction_s1(iptr));
-                       */
-                       escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_GLOBAL);
+                       /* If we return only arguments, the return value escapes only the method.
+                          ESCAPE_METHOD for now, and check later, if a different value than an
+                          argument is possibly returned. */
+                       escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD_RETURN);
+                       E("return", s1)
+                       instruction_list_add(e->returns, iptr);
                        break;
 
                case ICMD_ALOAD:
@@ -768,9 +988,6 @@ static void escape_analysis_process_instruction(escape_analysis_t *e, instructio
                case ICMD_MOVE:
                case ICMD_COPY:
                        if (instruction_dst_type(iptr, jd) == TYPE_ADR) {
-                               /*
-                               escape_analysis_assert_has_escape(e, instruction_s1(iptr));
-                               */
                                escape_analysis_merge(e, instruction_s1(iptr), instruction_dst(iptr));
                                escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
                        }
@@ -798,6 +1015,10 @@ static void escape_analysis_process_instructions(escape_analysis_t *e) {
 
        FOR_EACH_BASICBLOCK(e->jd, bptr) {
 
+               if (e->verbose) {
+                       color_printf(CYAN, "=== BB %d ===\n", bptr->nr);        
+               }
+
                for (iptr = bptr->phis; iptr != bptr->phis + bptr->phicount; ++iptr) {
                        escape_analysis_process_instruction(e, iptr);
                }
@@ -809,12 +1030,30 @@ static void escape_analysis_process_instructions(escape_analysis_t *e) {
        }
 }
 
+static void escape_analysis_post_process_returns(escape_analysis_t *e) {
+       instruction_list_item_t *iti;
+       instruction *iptr;
+
+       if (e->verbose) printf("Post processing returns:\n");
+
+       FOR_EACH_INSTRUCTION_LIST(e->getfields, iti) {
+               iptr = iti->instr;
+
+               if (! escape_analysis_get_contains_only_arguments(e, instruction_s1(iptr))) {
+                       escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_GLOBAL);
+                       E("return of not argument", s1)
+               }
+       }
+}
+
 static void escape_analysis_post_process_getfields(escape_analysis_t *e) {
        instruction_list_item_t *iti;
        dependency_list_item_t *itd;
        instruction *iptr;
        dependency_list_t *dl;
 
+       if (e->verbose) printf("Post processing getfields:\n");
+
        FOR_EACH_INSTRUCTION_LIST(e->getfields, iti) {
 
                iptr = iti->instr;
@@ -837,6 +1076,7 @@ static void escape_analysis_post_process_getfields(escape_analysis_t *e) {
                                                dependency_list_item_get_dependency(itd),
                                                escape_analysis_get_state(e, instruction_dst(iptr))
                                        );
+                                       I2("post process getfield", dependency_list_item_get_dependency(itd), escape_analysis_get_state(e, instruction_dst(iptr)));
                                }
                        }
                }
@@ -844,44 +1084,59 @@ static void escape_analysis_post_process_getfields(escape_analysis_t *e) {
        }
 }
 
-static void display_allocation(escape_analysis_t *e, const char *prefix, const instruction *iptr, escape_state_t es) {
-       const char *cl = "WTF";
-       classinfo *c;
+static void escape_analysis_mark_monitors(escape_analysis_t *e) {
+       instruction_list_item_t *iti;
+       instruction *iptr;
 
-       if (instruction_get_opcode(iptr) == ICMD_NEW) {
-               c = escape_analysis_classinfo_in_var(e, instruction_arg(iptr, 0));
-               if (c) {
-                       cl = c->name->text;
+       FOR_EACH_INSTRUCTION_LIST(e->monitors, iti) {
+               iptr = iti->instr;
+
+               /* TODO if argument does not escape, mark. */
+               if (escape_analysis_get_state(e, instruction_arg(iptr, 0)) != ESCAPE_GLOBAL) {
+                       if (e->verbose) {
+                               printf("Monitor on thread local object!\n");
+                       }
                }
        }
-       
-
-       printf(
-               " %s %s %s: %s %s @%d %s\n", 
-               prefix,
-               e->jd->m->clazz->name->text,
-               e->jd->m->name->text,
-               icmd_table[iptr->opc].name,
-               cl,
-               iptr->line,
-               escape_state_to_string(es)
-       );
 }
 
 static void escape_analysis_mark_allocations(escape_analysis_t *e) {
        instruction_list_item_t *iti;
+       instruction *iptr;
        escape_state_t es;
-/*
        FOR_EACH_INSTRUCTION_LIST(e->allocations, iti) {
-               es = escape_analysis_get_state(e, instruction_dst(iti->instr));
-               if (es < ESCAPE_GLOBAL_THROUGH_METHOD) {
-                       display_allocation(e, "****", iti->instr, es);
+               iptr = iti->instr;
+               es = escape_analysis_get_state(e, instruction_dst(iptr));
+
+#if defined(ENABLE_REASON)
+               if (instruction_get_opcode(iptr) == ICMD_NEW) {
+                       var_extra_t *ve;
+                       iptr->sx.s23.s3.bte = builtintable_get_internal(BUILTIN_escape_reason_new);
+                       ve = var_extra_get(e, var_extra_get_representant(e, instruction_dst(iptr)));
+                       iptr->escape_reasons = ve->reasons;
+                       if (es < ESCAPE_METHOD_RETURN) {
+                               assert(!ve->reasons);
+                               reason_t *r = NEW(reason_t);
+                               r->why = "No escape\n";
+                               r->iptr = NULL;
+                               r->next = NULL;
+                               iptr->escape_reasons = r;
+                       } else {
+                               assert(iptr->escape_reasons);
+                       }
                }
-               if (es == ESCAPE_GLOBAL_THROUGH_METHOD) {
-                       display_allocation(e, "!!!!", iti->instr, es);
+#endif
+
+/*
+               if (instruction_get_opcode(iptr) == ICMD_NEW) {
+                       es = escape_analysis_get_state(e, instruction_dst(iptr));
+                       if (es < ESCAPE_METHOD_RETURN) {
+                               iptr->sx.s23.s3.bte = builtintable_get_internal(BUILTIN_tlh_new);
+                               e->jd->code->flags |= CODE_FLAG_TLH;
+                       }
                }
-       }
 */
+       }
 }
 
 static void escape_analysis_process_arguments(escape_analysis_t *e) {
@@ -899,7 +1154,9 @@ static void escape_analysis_process_arguments(escape_analysis_t *e) {
                if (t == TYPE_ADR) {
                        if (varindex != UNUSED) {
                                escape_analysis_ensure_state(e, varindex, ESCAPE_NONE);
-                               escape_analysis_set_is_argument(e, varindex);
+                               escape_analysis_set_contains_argument(e, varindex);
+                               escape_analysis_set_contains_only_arguments(e, varindex);
+                               /*escape_analysis_set_adr_arg_num(e, varindex, e->adr_args_count);*/
                        }
                        e->adr_args_count += 1;
                }
@@ -914,11 +1171,18 @@ static void escape_analysis_export_arguments(escape_analysis_t *e) {
        s4 varindex;
        methoddesc *md;
        u1 *paramescape;
+       instruction_list_item_t *iti;
+       instruction *iptr;
+       escape_state_t es, re;
+       int ret_val_is_adr;
        
        md = e->jd->m->parseddesc;
 
-       paramescape = MNEW(u1, e->adr_args_count);
-       e->jd->m->paramescape = paramescape;
+       ret_val_is_adr = (md->returntype.type == TYPE_ADR) ? 1 : 0;
+
+       paramescape = MNEW(u1, e->adr_args_count + ret_val_is_adr);
+
+       e->jd->m->paramescape = paramescape + ret_val_is_adr;
 
        for (p = 0, l = 0; p < md->paramcount; ++p) {
                t = md->paramtypes[p].type;
@@ -927,17 +1191,60 @@ static void escape_analysis_export_arguments(escape_analysis_t *e) {
                        if (varindex == UNUSED) {
                                *paramescape = (u1)ESCAPE_NONE;
                        } else {
-                               *paramescape = (u1)escape_analysis_get_state(e, varindex);
-                       }
-                       if (e->verbose) {
-                               printf("adr parameter %d: %s\n", p, escape_state_to_string((escape_state_t)*paramescape));
+                               es = escape_analysis_get_state(e, varindex);
+
+                               if (es == ESCAPE_METHOD_RETURN) {
+                                       *paramescape = escape_state_to_u1(ESCAPE_METHOD) | 0x80;
+                                       if (e->verbose) {
+                                               printf("non-escaping adr parameter returned: %d\n", p);
+                                       }
+                               } else {
+                                       *paramescape = escape_state_to_u1(es);
+                               }
+
                        }
                        paramescape += 1;
                }
                l += IS_2_WORD_TYPE(t) ? 2 : 1;
        }
+
+       if (ret_val_is_adr) {
+               /* Calculate escape state of return value as maximum escape state of all
+                  values returned. */
+
+               re = ESCAPE_NONE;
+
+               FOR_EACH_INSTRUCTION_LIST(e->returns, iti) {
+                       iptr = iti->instr;
+                       es = escape_analysis_get_state(e, instruction_s1(iptr));
+
+                       if (es > re) {
+                               re = es;
+                       }
+               }
+
+               e->jd->m->paramescape[-1] = escape_state_to_u1(re);
+       }
 }
 
+#if defined(ENABLE_REASON)
+void print_escape_reasons() {
+       reason_t *re = THREADOBJECT->escape_reasons;
+
+       fprintf(stderr, "DYN_REASON");
+       
+       for (; re; re = re->next) {
+               fprintf(stderr,":%s", re->why);
+       }
+
+       fprintf(stderr, "\n");
+}
+
+void set_escape_reasons(void *vp) {
+       THREADOBJECT->escape_reasons = vp;
+}
+#endif
+
 static void escape_analysis_display(escape_analysis_t *e) {
        instruction_list_item_t *iti;
        var_extra_t *ve;
@@ -945,13 +1252,26 @@ static void escape_analysis_display(escape_analysis_t *e) {
 
        FOR_EACH_INSTRUCTION_LIST(e->allocations, iti) {
                iptr = iti->instr;
-               ve = var_extra_get(e, instruction_dst(iptr));
+               ve = var_extra_get(e, var_extra_get_representant(e, instruction_dst(iptr)));
+               show_icmd(e->jd, iptr-1, 0, 3);
+               printf("\n");
+               show_icmd(e->jd, iptr, 0, 3);
+               printf("\n");
                printf(
-                       "%s@%d: %s\n", 
+                       "%s@%d: --%s-- %d\n\n", 
                        icmd_table[iptr->opc].name, 
                        iptr->line, 
-                       escape_state_to_string(ve->escape_state)
+                       escape_state_to_string(ve->escape_state),
+                       ve->representant
                );
+#if defined(ENABLE_REASON)
+               {
+                       reason_t *re;
+                       for (re = ve->reasons; re; re = re->next) {
+                               printf("ESCAPE_REASON: %s\n", re->why);
+                       }
+               }
+#endif
        }
 }
 
@@ -960,23 +1280,72 @@ void escape_analysis_perform(jitdata *jd) {
 
        jd->m->flags |= ACC_METHOD_EA;
 
-       /*bc_escape_analysis_perform(jd->m);*/
-
        e = DNEW(escape_analysis_t);
        escape_analysis_init(e, jd);
 
        if (e->verbose) 
-               printf("==== %s/%s ====\n", e->jd->m->clazz->name->text, e->jd->m->name->text);
+               color_printf(RED, "\n\n==== %s/%s ====\n\n", e->jd->m->clazz->name->text, e->jd->m->name->text);
                
-       /*fprintf(stderr, ".");*/
-
        escape_analysis_process_arguments(e);
        escape_analysis_process_instructions(e);
        escape_analysis_post_process_getfields(e);
+       escape_analysis_post_process_returns(e);
+
        escape_analysis_export_arguments(e);
        if (e->verbose) escape_analysis_display(e);
+
+       if (e->verbose) {
+               int i, j, r;
+               for (i = 0; i < jd->vartop; ++i) {
+                       r = var_extra_get_representant(e, i);
+                       if (i == r) {
+                               printf("EES of %d: ", i);
+                               for (j = 0; j < jd->vartop; ++j) {
+                                       if (var_extra_get_representant(e, j) == r) {
+                                               printf("%d, ", j);
+                                       }
+                               }
+                               printf("\n");
+                       }
+               }
+               printf("\n");
+       }
+
        escape_analysis_mark_allocations(e);
+       escape_analysis_mark_monitors(e);
 
        jd->m->flags &= ~ACC_METHOD_EA;
 }
 
+void escape_analysis_escape_check(void *vp) {
+}
+
+/*** monomorphic *************************************************************/
+
+bool escape_is_monomorphic(methodinfo *caller, methodinfo *callee) {
+
+       /* Non-speculative case */
+
+       if (callee->flags & (ACC_STATIC | ACC_FINAL | ACC_PRIVATE)) {
+               return true;
+       }
+
+       if (
+               (callee->flags & (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED| ACC_ABSTRACT))
+               == (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED)
+       ) {
+
+               /* Mark that we have used the information about monomorphy. */
+
+               callee->flags |= ACC_METHOD_MONOMORPHY_USED;
+
+               /* We assume the callee is monomorphic. */
+
+               method_add_assumption_monomorphic(caller, callee);
+
+               return true;
+       }
+
+       return false;
+}
+