op_stack_slot_t *ptr;
op_stack_slot_t *bottom;
unsigned max;
+ bool *perror_flag;
} op_stack_t;
-#define stack_assert_position(stack, pos) \
- do { \
- assert((stack)->elements <= (pos)); \
- assert((pos) < (stack)->end); \
- } while (0)
-
-static void op_stack_init(op_stack_t *stack, unsigned max) {
+static void op_stack_init(op_stack_t *stack, unsigned max, bool *perror_flag) {
op_stack_slot_t *it;
stack->elements = DMNEW(op_stack_slot_t, max * 2);
stack->ptr = stack->start;
stack->bottom = stack->start;
+
+ stack->perror_flag = perror_flag;
+}
+
+static void op_stack_set_error(op_stack_t *stack) {
+ *(stack->perror_flag) = true;
+#if BC_ESCAPE_VERBOSE
+ printf("%s: error.\n", __FUNCTION__);
+#endif
+}
+
+static bool op_stack_test_position(op_stack_t *stack, op_stack_slot_t *pos) {
+ if (!(stack->elements <= pos)) {
+ op_stack_set_error(stack);
+ return false;
+ } else if (!(pos < stack->end)) {
+ op_stack_set_error(stack);
+ return false;
+ } else {
+ return true;
+ }
}
static void op_stack_reset(op_stack_t *stack) {
static op_stack_slot_t op_stack_pop(op_stack_t *stack) {
op_stack_slot_t ret;
stack->ptr -= 1;
- stack_assert_position(stack, stack->ptr);
+ if (! op_stack_test_position(stack, stack->ptr)) {
+ return OP_STACK_SLOT_UNKNOWN;
+ }
ret = *(stack->ptr);
if (stack->ptr < stack->bottom) {
stack->bottom = stack->ptr;
}
static void op_stack_push(op_stack_t *stack, op_stack_slot_t element) {
- stack_assert_position(stack, stack->ptr);
- *(stack->ptr) = element;
- stack->ptr += 1;
+ if (op_stack_test_position(stack, stack->ptr)) {
+ *(stack->ptr) = element;
+ stack->ptr += 1;
+ }
}
static op_stack_slot_t op_stack_get(const op_stack_t *stack, int offset) {
- stack_assert_position(stack, stack->ptr - offset);
- return *(stack->ptr - offset);
+ if (op_stack_test_position(stack, stack->ptr - offset)) {
+ return *(stack->ptr - offset);
+ } else {
+ return OP_STACK_SLOT_UNKNOWN;
+ }
}
static void op_stack_set(op_stack_t *stack, int offset, op_stack_slot_t value) {
- stack_assert_position(stack, stack->ptr - offset);
- *(stack->ptr - offset) = value;
+ if (op_stack_test_position(stack, stack->ptr - offset)) {
+ *(stack->ptr - offset) = value;
+ }
}
static inline void op_stack_push_unknown(op_stack_t *stack) {
u1 *pos;
u1 *instruction_start;
s4 offset;
+ bool *perror_flag;
} jcode_t;
-static void jcode_init(jcode_t *jc, u1 *start, s4 length, s4 offset) {
+static void jcode_init(jcode_t *jc, u1 *start, s4 length, s4 offset, bool *perror_flag) {
jc->start = start;
jc->end = jc->start + length;
jc->pos = jc->start;
jc->offset = offset;
+ jc->perror_flag = perror_flag;
+}
+
+static void jcode_set_error(jcode_t *jc) {
+ *(jc->perror_flag) = true;
+#if BC_ESCAPE_VERBOSE
+ printf("%s: error.\n", __FUNCTION__);
+#endif
}
static void jcode_move_to_index(jcode_t *jc, s4 index) {
return jc->offset + (jc->pos - jc->start);
}
-#define jcode_assert_has_bytes(jc, n) \
- assert((jc->pos + n) <= jc->end)
+bool jcode_test_has_bytes(jcode_t *jc, s4 n) {
+ if ((jc->pos + n) <= jc->end) {
+ return true;
+ } else {
+ jcode_set_error(jc);
+ return false;
+ }
+}
static u1 jcode_get_u1(jcode_t *jc) {
u1 ret;
- jcode_assert_has_bytes(jc, 1);
- ret = jc->pos[0];
- jc->pos += 1;
+ if (jcode_test_has_bytes(jc, 1)) {
+ ret = jc->pos[0];
+ jc->pos += 1;
+ } else {
+ ret = 0;
+ }
return ret;
}
static s2 jcode_get_s2(jcode_t *jc) {
s2 ret;
- jcode_assert_has_bytes(jc, 2);
- ret = (jc->pos[0] << 8) | (jc->pos[1]);
- jc->pos += 2;
+ if (jcode_test_has_bytes(jc, 2)) {
+ ret = (jc->pos[0] << 8) | (jc->pos[1]);
+ jc->pos += 2;
+ } else {
+ ret = 0;
+ }
return ret;
}
static u2 jcode_get_u2(jcode_t *jc) {
u2 ret;
- jcode_assert_has_bytes(jc, 2);
- ret = (jc->pos[0] << 8) | (jc->pos[1]);
- jc->pos += 2;
+ if (jcode_test_has_bytes(jc, 2)) {
+ ret = (jc->pos[0] << 8) | (jc->pos[1]);
+ jc->pos += 2;
+ } else {
+ ret = 0;
+ }
return ret;
}
static s4 jcode_get_s4(jcode_t *jc) {
s4 ret;
- jcode_assert_has_bytes(jc, 4);
- ret = (jc->pos[0] << 24) | (jc->pos[1] << 16) | (jc->pos[2] << 8) | (jc->pos[3]);
- jc->pos += 4;
+ if (jcode_test_has_bytes(jc, 4)) {
+ ret = (jc->pos[0] << 24) | (jc->pos[1] << 16) | (jc->pos[2] << 8) | (jc->pos[3]);
+ jc->pos += 4;
+ } else {
+ ret = 0;
+ }
return ret;
}
static s4 jcode_get_fall_through_target(jcode_t *jc) {
int length = bytecode[*jc->instruction_start].length;
- assert(length > 0);
+ if (length <= 0) {
+ jcode_set_error(jc);
+ }
return jc->offset + (jc->instruction_start - jc->start) + length;
}
bool verbose;
#endif
int depth;
+
+ bool fatal_error;
} bc_escape_analysis_t;
static void bc_escape_analysis_perform_intern(methodinfo *m, int depth);
int a;
u1 *ite;
u1 t;
- int ret_adr;
unsigned n;
+ int ret_val_is_adr;
be->method = m;
be->stack = DNEW(op_stack_t);
- op_stack_init(be->stack, m->maxstack);
+ op_stack_init(be->stack, m->maxstack, &(be->fatal_error));
be->basicblocks = DNEW(basicblock_work_list_t);
basicblock_work_list_init(be->basicblocks);
assert(l == be->local_to_adr_param_size);
- /* Determine whether return type is address */
-
- ret_adr = m->parseddesc->returntype.type == TYPE_ADR ? 1 : 0;
+ ret_val_is_adr = m->parseddesc->returntype.type == TYPE_ADR ? 1 : 0;
/* Allocate param_escape on heap. */
be->param_escape_size = a;
- n = a + ret_adr;
+ n = a + ret_val_is_adr;
if (n == 0) {
/* Use some non-NULL value. */
be->param_escape = (u1 *)1;
} else {
be->param_escape = MNEW(u1, n);
+ be->param_escape += ret_val_is_adr;
}
for (ite = be->param_escape; ite != be->param_escape + n; ++ite) {
- *ite = (u1)ESCAPE_NONE;
+ *ite = escape_state_to_u1(ESCAPE_NONE);
}
- be->param_escape += ret_adr;
+ if (ret_val_is_adr) {
+ be->param_escape[-1] = escape_state_to_u1(ESCAPE_NONE);
+ }
be->adr_param_dirty = DNEW(bit_vector_t);
bit_vector_init(be->adr_param_dirty, a);
#endif
be->depth = depth;
+
+ be->fatal_error = false;
}
static void bc_escape_analysis_branch_target(bc_escape_analysis_t *be, s4 branch_target) {
parameters. */
if (
- old < ESCAPE_GLOBAL_THROUGH_METHOD &&
- escape_state >= ESCAPE_GLOBAL_THROUGH_METHOD
+ old < ESCAPE_GLOBAL &&
+ escape_state >= ESCAPE_GLOBAL
) {
be->non_escaping_adr_params -= 1;
}
bc_escape_analysis_dirty(be, local + 1);
}
-static void bc_escape_analyisis_returned(bc_escape_analysis_t *be, op_stack_slot_t value) {
+static void bc_escape_analysis_returned(bc_escape_analysis_t *be, op_stack_slot_t value) {
if (op_stack_slot_is_param(value)) {
/* A parameter is returned, mark it as being returned. */
bit_vector_set(be->adr_param_returned, value.index);
- } else if (op_stack_slot_is_unknown(value)) {
- /* An untracked value is returned.
- Conservatively asume a globally escaping value is returned. */
+ /* The escape state of the return value will be adjusted later. */
+ } else {
+ /* Adjust escape state of return value. */
if (be->method->parseddesc->returntype.type == TYPE_ADR) {
- be->param_escape[-1] = (u1)ESCAPE_GLOBAL;
+ be->param_escape[-1] = escape_state_to_u1(ESCAPE_GLOBAL);
}
+ bc_escape_analysis_adjust_state(be, value, ESCAPE_GLOBAL);
}
}
}
}
+static void bc_escape_analysis_push_return_value(
+ bc_escape_analysis_t *be,
+ methoddesc *md
+) {
+ switch (md->returntype.type) {
+ case TYPE_LNG:
+ case TYPE_DBL:
+ op_stack_push_unknown(be->stack);
+ op_stack_push_unknown(be->stack);
+ break;
+ case TYPE_VOID:
+ /* Do nothing */
+ break;
+ default:
+ op_stack_push_unknown(be->stack);
+ break;
+ }
+}
+
static void bc_escape_analysis_adjust_invoke_parameters(
bc_escape_analysis_t *be,
methodinfo *mi
methoddesc *md = mi->parseddesc;
u1 *paramescape = mi->paramescape;
s4 stack_depth = md->paramslots;
+ unsigned num_params_returned = 0;
+ op_stack_slot_t param_returned;
/* Process parameters.
* The first parameter is at the highest depth on the stack.
for (i = 0; i < md->paramcount; ++i) {
switch (md->paramtypes[i].type) {
case TYPE_ADR:
+ if (*paramescape & 0x80) {
+ num_params_returned += 1;
+ param_returned = op_stack_get(be->stack, stack_depth);
+ }
bc_escape_analysis_adjust_state(
be,
op_stack_get(be->stack, stack_depth),
- (escape_state_t)*(paramescape++)
+ escape_state_from_u1(*paramescape++)
);
stack_depth -= 1;
break;
for (i = 0; i < md->paramslots; ++i) {
op_stack_pop(be->stack);
}
+
+ /* Push return value. */
+ if (md->returntype.type == TYPE_ADR) {
+ if ((num_params_returned == 1) && (mi->paramescape[-1] < ESCAPE_GLOBAL)) {
+ /* Only a single argument can be returned by the method,
+ and the retun value does not escape otherwise. */
+ op_stack_push(be->stack, param_returned);
+ } else {
+ op_stack_push_unknown(be->stack);
+ }
+ } else {
+ bc_escape_analysis_push_return_value(be, md);
+ }
}
static void bc_escape_analysis_escape_invoke_parameters(
for (i = 0; i < md->paramslots; ++i) {
bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
}
+
+ bc_escape_analysis_push_return_value(be, md);
}
static void bc_escape_analysis_parse_invoke(bc_escape_analysis_t *be, jcode_t *jc) {
or recurse into callee.
Otherwise we must assume, that all parameters escape. */
- if (mi != NULL) {
+ if (mi != NULL && method_profile_is_monomorphic(mi)) {
if (mi->paramescape == NULL) {
bc_escape_analysis_perform_intern(mi, be->depth + 1);
} else {
bc_escape_analysis_escape_invoke_parameters(be, md);
}
-
- switch (md->returntype.type) {
- case TYPE_LNG:
- case TYPE_DBL:
- op_stack_push_unknown(be->stack);
- op_stack_push_unknown(be->stack);
- break;
- case TYPE_VOID:
- /* Do nothing */
- break;
- default:
- op_stack_push_unknown(be->stack);
- break;
- }
}
static void bc_escape_analysis_parse_tableswitch(
/* TODO end if all parameters escape */
/* TODO move code into process_instruction or the like */
- while ((! jcode_end(jc)) && (! bb_end)) {
+ while ((! jcode_end(jc)) && (! bb_end) && (! be->fatal_error)) {
jcode_record_instruction_start(jc);
case BC_areturn:
/* FIXME */
- bc_escape_analyisis_returned(be, op_stack_pop(be->stack));
+ bc_escape_analysis_returned(be, op_stack_pop(be->stack));
bb_end = true;
break;
}
#endif
- while (! op_stack_is_empty(be->stack)) {
+ while ((! op_stack_is_empty(be->stack)) && (! be->fatal_error)) {
#if BC_ESCAPE_VERBOSE
if (be->verbose) {
dprintf(be->depth, "Stack element: ");
}
#endif
}
+
+ if (be->fatal_error) {
+#if BC_ESCAPE_VERBOSE
+ if (be->verbose) {
+ printf("Fatal error while processing basic block. Aborting.\n");
+ }
+#endif
+ assert(0);
+ }
}
static void bc_escape_analysis_adjust_return_value(bc_escape_analysis_t *be) {
- escape_state_t e, pe;
+ escape_state_t re, pe;
int i;
/* Only calculate, if return value is of type address. */
return ;
}
- /* Get current escape state of return value. */
-
- e = (escape_state_t)be->param_escape[-1];
-
/* If a parameter can be returned, adjust to its escape state. */
for (i = 0; i < be->param_escape_size; ++i) {
if (bit_vector_get(be->adr_param_returned, i)) {
- pe = (escape_state_t)be->param_escape[i];
- if (pe > e) {
- e = pe;
+ be->param_escape[i] |= 0x80;
+
+ pe = escape_state_from_u1(be->param_escape[i]);
+ re = escape_state_from_u1(be->param_escape[-1]);
+
+ if (pe > re) {
+ be->param_escape[-1] = escape_state_to_u1(pe);
}
}
}
-
- be->param_escape[-1] = (u1)e;
}
static void bc_escape_analysis_analyze(bc_escape_analysis_t *be) {
&jc,
be->method->jcode,
be->method->jcodelength,
- 0
+ 0,
+ &(be->fatal_error)
);
/* Process basicblock by basicblock. */
-/* src/vm/optimizing/escape.c
+/* srcontainsc/vm/optimizing/escape.c
Copyright (C) 2008
CACAOVM - Verein zu Foerderung der freien virtuellen Machine CACAO
#include "vm/jit/jit.h"
#include "vmcore/class.h"
+#include "vmcore/classcache.h"
#include "vm/jit/optimizing/escape.h"
/*** 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;
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;*/
} 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;*/
}
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);
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_extra_get(e, var)->contains_arg = true;
+}
+
+static bool escape_analysis_get_contains_argument(escape_analysis_t *e, s4 var) {
+ return var_extra_get(e, var)->contains_arg;
+}
+
+static void escape_analysis_set_contains_only_arguments(escape_analysis_t *e, s4 var) {
+ var_extra_get(e, var)->contains_only_args = true;
+}
+
+static bool escape_analysis_get_contains_only_arguments(escape_analysis_t *e, s4 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) {
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);
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);
);
}
}
+
+ /* 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;
+ }
+ */
}
static void escape_analysis_add_dependency(escape_analysis_t *e, instruction *store) {
u1 *paramescape;
unsigned i;
instruction **iarg;
- constant_FMIref *fmi;
methodinfo *mi;
- resolve_result_t result;
+ escape_state_t es;
if (e->verbose) {
printf("processing %s@%d\n", icmd_table[iptr->opc].name, iptr->line);
if (c == NULL) {
escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
- if (e->verbose) printf("1\n");
} else if (c->finalizer != NULL) {
escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
- if (e->verbose) printf("3\n");
} 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:
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);
}
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. */
} else {
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))) {
escape_analysis_ensure_state(e, instruction_s3(iptr), ESCAPE_GLOBAL);
} else {
escape_analysis_ensure_state(e, instruction_s3(iptr), escape_analysis_get_state(e, instruction_s1(iptr)));
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;
break;
case ICMD_ARRAYLENGTH:
- /*
- escape_analysis_assert_has_escape(e, instruction_s1(iptr));
- */
+ /* TODO */
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);
} else {
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:
case ICMD_CHECKNULL:
- /*
- escape_analysis_assert_has_escape(e, instruction_s1(iptr));
- */
escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
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;
if (paramescape == NULL) {
if (e->verbose) {
- printf("BC escape analyzing callee.\n");
+ printf("BC escape analyzing callee %s/%s.\n", mi->clazz->name->text, mi->name->text);
}
bc_escape_analysis_perform(mi);
paramescape = mi->paramescape;
}
}
+ if (iptr->opc == ICMD_INVOKEVIRTUAL || iptr->opc == ICMD_INVOKEINTERFACE) {
+ if (mi != NULL && !method_profile_is_monomorphic(mi)) {
+ 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);
+ } else {
+ es = escape_state_from_u1(paramescape[-1]);
+ 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);
- } else {
- escape_analysis_ensure_state(e, instruction_arg(iptr, i), (escape_state_t)*paramescape);
+ } else if (escape_state_from_u1(*paramescape) < ESCAPE_METHOD) {
+ es = escape_state_from_u1(*paramescape);
+
+ if (es < ESCAPE_METHOD) {
+ es = ESCAPE_METHOD;
+ }
+
+ 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));
+ }
}
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);
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);
+ 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);
}
}
}
+static void escape_analysis_post_process_returns(escape_analysis_t *e) {
+ instruction_list_item_t *iti;
+ instruction *iptr;
+
+ 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);
+ }
+ }
+}
+
static void escape_analysis_post_process_getfields(escape_analysis_t *e) {
instruction_list_item_t *iti;
dependency_list_item_t *itd;
}
}
+static void escape_analysis_mark_monitors(escape_analysis_t *e) {
+ instruction_list_item_t *iti;
+ instruction *iptr;
+
+ 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) {
+ printf("Monitor on thread local object!\n");
+ }
+ }
+}
+
static void display_allocation(escape_analysis_t *e, const char *prefix, const instruction *iptr, escape_state_t es) {
const char *cl = "WTF";
classinfo *c;
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);
+ }
}
static void escape_analysis_display(escape_analysis_t *e) {
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);
- /*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);
+
escape_analysis_mark_allocations(e);
+ escape_analysis_mark_monitors(e);
jd->m->flags &= ~ACC_METHOD_EA;
}
void escape_analysis_escape_check(void *vp) {
}
+
+/*** monomorphic *************************************************************/
+
+monomorphic_t monomorphic_get(methodinfo *caller, methodinfo *callee) {
+ monomorphic_t res = { 0, 0 };
+}
+
+#if 0
+
+/*** HACK to store method monomorphy information upon shutdown ****************/
+
+#include <sqlite3.h>
+
+bool method_profile_is_monomorphic(methodinfo *m) {
+ static sqlite3 *db = NULL;
+ static sqlite3_stmt *stmt = NULL;
+ int ret;
+
+ if (db == NULL) {
+ assert(sqlite3_open("/home/peter/cacao-dev/profile.sqlite", &db) == SQLITE_OK);
+ assert(sqlite3_prepare(db, "SELECT count(*) FROM monomorphic where class=? and method=? and descriptor=?", -1, &stmt, 0) == SQLITE_OK);
+ }
+
+ assert(sqlite3_bind_text(stmt, 1, m->clazz->name->text, -1, SQLITE_STATIC) == SQLITE_OK);
+ assert(sqlite3_bind_text(stmt, 2, m->name->text, -1, SQLITE_STATIC) == SQLITE_OK);
+ assert(sqlite3_bind_text(stmt, 3, m->descriptor->text, -1, SQLITE_STATIC) == SQLITE_OK);
+
+ assert(sqlite3_step(stmt) == SQLITE_ROW);
+ ret = sqlite3_column_int(stmt, 0);
+ assert(sqlite3_reset(stmt) == SQLITE_OK);
+
+ return ret;
+}
+void func(classinfo *c, void *arg) {
+ methodinfo *it;
+ sqlite3_stmt *stmt = (sqlite3_stmt *)arg;
+ s4 flags;
+ for (it = c->methods; it != c->methods + c->methodscount; ++it) {
+ flags = it->flags;
+ if (flags & (ACC_STATIC | ACC_FINAL | ACC_PRIVATE)) {
+ continue;
+ }
+ if ((flags & (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED | ACC_ABSTRACT)) ==
+ (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED)) {
+ assert(sqlite3_bind_text(stmt, 1, c->name->text, -1, SQLITE_STATIC) == SQLITE_OK);
+ assert(sqlite3_bind_text(stmt, 2, it->name->text, -1, SQLITE_STATIC) == SQLITE_OK);
+ assert(sqlite3_bind_text(stmt, 3, it->descriptor->text, -1, SQLITE_STATIC) == SQLITE_OK);
+
+ assert(sqlite3_step(stmt) == SQLITE_DONE);
+ assert(sqlite3_reset(stmt) == SQLITE_OK);
+ }
+ }
+}
+
+
+void method_profile_store() {
+ sqlite3 *db = NULL;
+ sqlite3_stmt *stmt;
+ assert(sqlite3_open("/home/peter/cacao-dev/profile.sqlite", &db) == SQLITE_OK);
+ assert(sqlite3_exec(db, "DELETE FROM monomorphic", NULL, NULL, NULL) == SQLITE_OK);
+ assert(sqlite3_prepare(db, "INSERT INTO monomorphic (class, method, descriptor) VALUES (?,?,?)", -1, &stmt, 0) == SQLITE_OK);
+ classcache_foreach_loaded_class(func, stmt);
+ assert(sqlite3_finalize(stmt) == SQLITE_OK);
+ assert(sqlite3_close(db) == SQLITE_OK);
+}
+
+void iterate_classes() {
+ return;
+ method_profile_store();
+
+}
+
+#endif
+
+#if defined(ENABLE_TLH)
+/*** TLH (Thread local heap) hack ********************************************/
+
+#include <sys/mman.h>
+#include "threads/thread.h"
+
+#define TLH_MAX_SIZE (20 * 1024 * 1024)
+
+void tlh_init(threadobject *t) {
+ uint8_t *heap = (uint8_t *)mmap(
+ NULL,
+ TLH_MAX_SIZE,
+ PROT_READ|PROT_WRITE,
+ MAP_ANONYMOUS|MAP_PRIVATE,
+ -1,
+ 0
+ );
+ uint8_t *red = (uint8_t *)mmap(
+ heap + TLH_MAX_SIZE - getpagesize(),
+ getpagesize(),
+ PROT_NONE,
+ MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED,
+ -1,
+ 0
+ );
+ assert(heap);
+ assert(red);
+ t->tlhstart = heap;
+ t->tlhtop = heap;
+ t->tlhbase = heap;
+}
+
+void tlh_reset(threadobject *t) {
+ t->tlhtop = t->tlhstart;
+ t->tlhbase = t->tlhstart;
+}
+
+void tlh_destroy(threadobject *t) {
+ int res = munmap(t->tlhstart, TLH_MAX_SIZE - getpagesize());
+ int res2 = munmap(t->tlhstart + TLH_MAX_SIZE - getpagesize(), getpagesize());
+ assert(res);
+ assert(res2);
+}
+
+bool tlh_sigsegv_handler(void *addr) {
+}
+
+#endif