-#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) {
str(ESCAPE_UNKNOWN)
str(ESCAPE_NONE)
str(ESCAPE_METHOD)
- str(ESCAPE_GLOBAL_THROUGH_METHOD)
+ str(ESCAPE_METHOD_RETURN)
str(ESCAPE_GLOBAL)
default: return "???";
}
instruction_list_t *allocations;
instruction_list_t *getfields;
+ instruction_list_t *monitors;
+ instruction_list_t *returns;
struct var_extra **var;
/*** 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) {
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) {
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;
}
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) {
dependency_list_item_get_dependency(it),
escape_state
);
+ {
+ instruction *iptr = NULL;
+ I2("propagated by dependency", dependency_list_item_get_dependency(it), escape_state);
+ }
}
}
}
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);
return;
}
+ if (e->verbose) printf("Merging (%d,%d)\n", var1, var2);
+
ve1 = var_extra_get(e, var1);
ve2 = var_extra_get(e, 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);
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) {
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");
}
}
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)) {
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);
}
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);
}
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);
}
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);
}
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;
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;
}
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) {
}
}
- 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:
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);
}
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);
}
}
}
+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;
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)));
}
}
}
}
}
-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) {
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;
}
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;
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;
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
}
}
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;
+}
+