1 /* src/vm/optimizing/bytecode_escape.c
4 CACAOVM - Verein zu Foerderung der freien virtuellen Machine CACAO
6 This file is part of CACAO.
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2, or (at
11 your option) any later version.
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 #include "mm/dumpmemory.h"
25 #include "mm/memory.h"
27 #include "toolbox/bitvector.h"
29 #include "vm/global.h"
30 #include "vm/jit/ir/bytecode.h"
31 #include "vm/jit/optimizing/escape.h"
32 #include "vm/resolve.h"
34 #include "vmcore/class.h"
35 #include "vmcore/descriptor.h"
36 #include "vmcore/references.h"
41 #define BC_ESCAPE_VERBOSE !defined(NDEBUG)
43 /*** dprintf *****************************************************************/
45 #if BC_ESCAPE_VERBOSE && 0
46 void dprintf(int depth, const char *fmt, ...) {
60 #define dprintf(x, ...) printf(__VA_ARGS__)
62 /*** op_stack_slot **********************************************************/
65 OP_STACK_SLOT_TYPE_PARAM = 0,
66 OP_STACK_SLOT_TYPE_UNKNOWN = 1
67 } op_stack_slot_type_t;
74 const op_stack_slot_t OP_STACK_SLOT_UNKNOWN = {
75 OP_STACK_SLOT_TYPE_UNKNOWN,
79 static inline op_stack_slot_t op_stack_slot_create_param(s4 index) {
81 res.type = OP_STACK_SLOT_TYPE_PARAM;
86 static inline bool op_stack_slot_is_unknown(const op_stack_slot_t slot) {
87 return slot.type == OP_STACK_SLOT_TYPE_UNKNOWN;
90 static inline bool op_stack_slot_is_param(const op_stack_slot_t slot) {
91 return slot.type == OP_STACK_SLOT_TYPE_PARAM;
94 /*** op_stack *****************************************************************/
98 +---+---+---+---+ push 1
101 +---+---+-1-+---+ push 2
104 +---+---+-1-+-2-+ pop 2
107 +---+---+-1-+---+ pop 1
115 op_stack_slot_t *elements;
116 op_stack_slot_t *start;
117 op_stack_slot_t *end;
118 op_stack_slot_t *ptr;
119 op_stack_slot_t *bottom;
124 static void op_stack_init(op_stack_t *stack, unsigned max, bool *perror_flag) {
127 stack->elements = DMNEW(op_stack_slot_t, max * 2);
129 stack->start = stack->elements + max;
130 stack->end = stack->elements + max + max;
132 for (it = stack->elements; it != stack->start; ++it) {
133 *it = OP_STACK_SLOT_UNKNOWN;
136 stack->ptr = stack->start;
137 stack->bottom = stack->start;
139 stack->perror_flag = perror_flag;
142 static void op_stack_set_error(op_stack_t *stack) {
143 *(stack->perror_flag) = true;
144 #if BC_ESCAPE_VERBOSE
145 printf("%s: error.\n", __FUNCTION__);
149 static bool op_stack_test_position(op_stack_t *stack, op_stack_slot_t *pos) {
150 if (!(stack->elements <= pos)) {
151 op_stack_set_error(stack);
153 } else if (!(pos < stack->end)) {
154 op_stack_set_error(stack);
161 static void op_stack_reset(op_stack_t *stack) {
164 /* Clear bottom half. */
166 for (it = stack->bottom; it != stack->elements + stack->max; ++it) {
167 *it = OP_STACK_SLOT_UNKNOWN;
170 /* Reset pointers. */
172 stack->ptr = stack->start;
173 stack->bottom = stack->start;
176 static op_stack_slot_t op_stack_pop(op_stack_t *stack) {
179 if (! op_stack_test_position(stack, stack->ptr)) {
180 return OP_STACK_SLOT_UNKNOWN;
183 if (stack->ptr < stack->bottom) {
184 stack->bottom = stack->ptr;
189 static void op_stack_push(op_stack_t *stack, op_stack_slot_t element) {
190 if (op_stack_test_position(stack, stack->ptr)) {
191 *(stack->ptr) = element;
196 static op_stack_slot_t op_stack_get(const op_stack_t *stack, int offset) {
197 if (op_stack_test_position(stack, stack->ptr - offset)) {
198 return *(stack->ptr - offset);
200 return OP_STACK_SLOT_UNKNOWN;
204 static void op_stack_set(op_stack_t *stack, int offset, op_stack_slot_t value) {
205 if (op_stack_test_position(stack, stack->ptr - offset)) {
206 *(stack->ptr - offset) = value;
210 static inline void op_stack_push_unknown(op_stack_t *stack) {
211 op_stack_push(stack, OP_STACK_SLOT_UNKNOWN);
214 static void op_stack_print(const op_stack_t *stack, FILE *f) {
218 for (it = stack->bottom; it < stack->ptr; ++it) {
219 if (it == stack->start) {
224 if (op_stack_slot_is_unknown(*it)) {
225 fprintf(f, "%c----", sep);
227 fprintf(f, "%cP%3d", sep, it->index);
234 static bool op_stack_is_empty(const op_stack_t *stack) {
235 return !(stack->bottom < stack->ptr);
238 static s4 op_stack_element_count(const op_stack_t *stack) {
239 return (stack->ptr - stack->bottom);
242 /*** bit_vector **************************************************************/
249 static void bit_vector_init(bit_vector_t *bv, s4 size) {
250 bv->bv = bv_new(size);
254 static s4 bit_vector_size(const bit_vector_t *bv) {
258 static void bit_vector_set(bit_vector_t *bv, s4 bit) {
259 assert(0 <= bit && bit < bv->size);
260 bv_set_bit(bv->bv, bit);
263 static bool bit_vector_get(const bit_vector_t *bv, s4 bit) {
264 assert(0 <= bit && bit < bv->size);
265 return bv_get_bit(bv->bv, bit);
268 /*** basicblock_work_list ***********************************************/
270 typedef struct basicblock_work_item {
272 struct basicblock_work_item *next;
273 } basicblock_work_item_t;
276 basicblock_work_item_t *first;
277 basicblock_work_item_t *last;
278 } basicblock_work_list_t;
280 void basicblock_work_list_init(basicblock_work_list_t *lst) {
285 #define FOR_EACH_BASICBLOCK_WORK_LIST(lst, it) \
286 for ((it) = (lst)->first; (it); (it) = (it)->next)
288 void basicblock_work_list_insert(basicblock_work_list_t *lst, s4 bytecode_index) {
289 basicblock_work_item_t *it, *item;
291 /* If the destination is already present in the list, do nothing. */
293 FOR_EACH_BASICBLOCK_WORK_LIST(lst, it) {
294 if (it->bytecode_index == bytecode_index) {
299 item = DNEW(basicblock_work_item_t);
300 item->bytecode_index = bytecode_index;
303 if (lst->first == NULL) {
307 lst->last->next = item;
312 /*** value_category *****************************************************/
319 /*** jcode **************************************************************/
325 u1 *instruction_start;
330 static void jcode_init(jcode_t *jc, u1 *start, s4 length, s4 offset, bool *perror_flag) {
332 jc->end = jc->start + length;
335 jc->perror_flag = perror_flag;
338 static void jcode_set_error(jcode_t *jc) {
339 *(jc->perror_flag) = true;
340 #if BC_ESCAPE_VERBOSE
341 printf("%s: error.\n", __FUNCTION__);
345 static void jcode_move_to_index(jcode_t *jc, s4 index) {
346 jc->pos = jc->start + (index - jc->offset);
349 static bool jcode_end(const jcode_t *jc) {
350 return (jc->pos >= jc->end);
353 static void jcode_record_instruction_start(jcode_t *jc) {
354 jc->instruction_start = jc->pos;
357 static void jcode_rewind_instruction(jcode_t *jc) {
358 jc->pos = jc->instruction_start;
361 static s4 jcode_get_instruction_length(const jcode_t *jc) {
362 return (jc->pos - jc->instruction_start);
365 static void jcode_align_bytecode_index(jcode_t *jc, s4 align) {
368 idx = jc->offset + (jc->pos - jc->start);
369 aidx = MEMORY_ALIGN(idx, align);
371 jc->pos += (aidx - idx);
374 static void jcode_forward_instruction_relative(jcode_t *jc, s4 n) {
375 jc->pos = jc->instruction_start + n;
378 static s4 jcode_get_index(const jcode_t *jc) {
379 return jc->offset + (jc->pos - jc->start);
382 bool jcode_test_has_bytes(jcode_t *jc, s4 n) {
383 if ((jc->pos + n) <= jc->end) {
391 static u1 jcode_get_u1(jcode_t *jc) {
393 if (jcode_test_has_bytes(jc, 1)) {
402 static s2 jcode_get_s2(jcode_t *jc) {
404 if (jcode_test_has_bytes(jc, 2)) {
405 ret = (jc->pos[0] << 8) | (jc->pos[1]);
413 static u2 jcode_get_u2(jcode_t *jc) {
415 if (jcode_test_has_bytes(jc, 2)) {
416 ret = (jc->pos[0] << 8) | (jc->pos[1]);
424 static s4 jcode_get_s4(jcode_t *jc) {
426 if (jcode_test_has_bytes(jc, 4)) {
427 ret = (jc->pos[0] << 24) | (jc->pos[1] << 16) | (jc->pos[2] << 8) | (jc->pos[3]);
435 static s4 jcode_get_branch_target(jcode_t *jc) {
436 s2 off = jcode_get_s2(jc);
437 return jc->offset + (jc->instruction_start - jc->start) + off;
440 static s4 jcode_get_branch_target_wide(jcode_t *jc) {
441 s4 off = jcode_get_s4(jc);
442 return jc->offset + (jc->instruction_start - jc->start) + off;
445 static s4 jcode_get_fall_through_target(jcode_t *jc) {
446 int length = bytecode[*jc->instruction_start].length;
450 return jc->offset + (jc->instruction_start - jc->start) + length;
453 /*** bc_escape_analysis *************************************************/
458 basicblock_work_list_t *basicblocks;
460 op_stack_slot_t *local_to_adr_param;
461 s4 local_to_adr_param_size;
464 s4 param_escape_size;
466 bit_vector_t *adr_param_dirty;
467 bit_vector_t *adr_param_returned;
469 s4 non_escaping_adr_params;
471 #if BC_ESCAPE_VERBOSE
477 } bc_escape_analysis_t;
479 static void bc_escape_analysis_perform_intern(methodinfo *m, int depth);
481 static void bc_escape_analysis_init(bc_escape_analysis_t *be, methodinfo *m, bool verbose, int depth) {
492 be->stack = DNEW(op_stack_t);
493 op_stack_init(be->stack, m->maxstack, &(be->fatal_error));
495 be->basicblocks = DNEW(basicblock_work_list_t);
496 basicblock_work_list_init(be->basicblocks);
498 be->local_to_adr_param_size = m->parseddesc->paramslots;
499 be->local_to_adr_param = DMNEW(op_stack_slot_t, m->parseddesc->paramslots);
501 /* Count number of address parameters a. */
503 for (p = 0, l = 0, a = 0; p < m->parseddesc->paramcount; ++p) {
504 t = m->parseddesc->paramtypes[p].type;
506 be->local_to_adr_param[l] = op_stack_slot_create_param(a);
509 } else if (IS_2_WORD_TYPE(t)) {
510 be->local_to_adr_param[l] = OP_STACK_SLOT_UNKNOWN;
511 be->local_to_adr_param[l + 1] = OP_STACK_SLOT_UNKNOWN;
514 be->local_to_adr_param[l] = OP_STACK_SLOT_UNKNOWN;
519 assert(l == be->local_to_adr_param_size);
521 ret_val_is_adr = m->parseddesc->returntype.type == TYPE_ADR ? 1 : 0;
523 /* Allocate param_escape on heap. */
525 be->param_escape_size = a;
526 n = a + ret_val_is_adr;
529 /* Use some non-NULL value. */
530 be->param_escape = (u1 *)1;
532 be->param_escape = MNEW(u1, n);
533 be->param_escape += ret_val_is_adr;
536 for (ite = be->param_escape; ite != be->param_escape + n; ++ite) {
537 *ite = escape_state_to_u1(ESCAPE_NONE);
540 if (ret_val_is_adr) {
541 be->param_escape[-1] = escape_state_to_u1(ESCAPE_NONE);
544 be->adr_param_dirty = DNEW(bit_vector_t);
545 bit_vector_init(be->adr_param_dirty, a);
547 be->adr_param_returned= DNEW(bit_vector_t);
548 bit_vector_init(be->adr_param_returned, a);
550 be->non_escaping_adr_params = be->param_escape_size;
552 #if BC_ESCAPE_VERBOSE
553 be->verbose = verbose;
558 be->fatal_error = false;
561 static void bc_escape_analysis_branch_target(bc_escape_analysis_t *be, s4 branch_target) {
562 basicblock_work_list_insert(be->basicblocks, branch_target);
565 static void bc_escape_analysis_adjust_state(
566 bc_escape_analysis_t *be,
567 op_stack_slot_t adr_param,
568 escape_state_t escape_state
572 if (op_stack_slot_is_param(adr_param)) {
573 if (0 <= adr_param.index && adr_param.index < be->param_escape_size) {
574 old = (escape_state_t)be->param_escape[adr_param.index];
575 if (old < escape_state) {
577 /* Adjust escape state. */
578 be->param_escape[adr_param.index] = (u1)escape_state;
580 /* If the parameter has just escaped, decrement number of non-escaping
584 old < ESCAPE_GLOBAL &&
585 escape_state >= ESCAPE_GLOBAL
587 be->non_escaping_adr_params -= 1;
594 static void bc_escape_analysis_dirty(bc_escape_analysis_t *be, s4 local) {
595 op_stack_slot_t adr_param;
597 if (0 <= local && local < be->local_to_adr_param_size) {
598 adr_param = be->local_to_adr_param[local];
599 if (op_stack_slot_is_param(adr_param)) {
600 bit_vector_set(be->adr_param_dirty, adr_param.index);
605 static void bc_escape_analysis_dirty_2(bc_escape_analysis_t *be, s4 local) {
606 bc_escape_analysis_dirty(be, local);
607 bc_escape_analysis_dirty(be, local + 1);
610 static void bc_escape_analysis_returned(bc_escape_analysis_t *be, op_stack_slot_t value) {
611 if (op_stack_slot_is_param(value)) {
612 /* A parameter is returned, mark it as being returned. */
613 bit_vector_set(be->adr_param_returned, value.index);
614 /* The escape state of the return value will be adjusted later. */
616 /* Adjust escape state of return value. */
617 if (be->method->parseddesc->returntype.type == TYPE_ADR) {
618 be->param_escape[-1] = escape_state_to_u1(ESCAPE_GLOBAL);
620 bc_escape_analysis_adjust_state(be, value, ESCAPE_GLOBAL);
624 op_stack_slot_t bc_escape_analysis_address_local(bc_escape_analysis_t *be, s4 local) {
625 if (0 <= local && local < be->local_to_adr_param_size) {
626 return be->local_to_adr_param[local];
628 return OP_STACK_SLOT_UNKNOWN;
632 value_category_t bc_escape_analysis_value_category(bc_escape_analysis_t *be, s4 index) {
633 constant_FMIref *fmi;
634 fmi = class_getconstant(be->method->clazz, index, CONSTANT_Fieldref);
641 switch (fmi->parseddesc.fd->type) {
644 return VALUE_CATEGORY_2;
646 return VALUE_CATEGORY_1;
650 static void bc_escape_analysis_push_return_value(
651 bc_escape_analysis_t *be,
654 switch (md->returntype.type) {
657 op_stack_push_unknown(be->stack);
658 op_stack_push_unknown(be->stack);
664 op_stack_push_unknown(be->stack);
669 static void bc_escape_analysis_adjust_invoke_parameters(
670 bc_escape_analysis_t *be,
674 methoddesc *md = mi->parseddesc;
675 u1 *paramescape = mi->paramescape;
676 s4 stack_depth = md->paramslots;
677 unsigned num_params_returned = 0;
678 op_stack_slot_t param_returned;
680 /* Process parameters.
681 * The first parameter is at the highest depth on the stack.
684 for (i = 0; i < md->paramcount; ++i) {
685 switch (md->paramtypes[i].type) {
687 if (*paramescape & 0x80) {
688 num_params_returned += 1;
689 param_returned = op_stack_get(be->stack, stack_depth);
691 bc_escape_analysis_adjust_state(
693 op_stack_get(be->stack, stack_depth),
694 escape_state_from_u1(*paramescape++)
708 /* Pop all parameters. */
710 for (i = 0; i < md->paramslots; ++i) {
711 op_stack_pop(be->stack);
714 /* Push return value. */
716 if (md->returntype.type == TYPE_ADR) {
717 if ((num_params_returned == 1) && (mi->paramescape[-1] < ESCAPE_GLOBAL)) {
718 /* Only a single argument can be returned by the method,
719 and the retun value does not escape otherwise. */
720 op_stack_push(be->stack, param_returned);
722 op_stack_push_unknown(be->stack);
725 bc_escape_analysis_push_return_value(be, md);
729 static void bc_escape_analysis_escape_invoke_parameters(
730 bc_escape_analysis_t *be,
734 for (i = 0; i < md->paramslots; ++i) {
735 bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
738 bc_escape_analysis_push_return_value(be, md);
741 static void bc_escape_analysis_parse_invoke(bc_escape_analysis_t *be, jcode_t *jc) {
742 constant_FMIref *fmi;
747 resolve_result_t result;
750 opc = jcode_get_u1(jc);
751 cp_index = jcode_get_u2(jc);
753 /* Get method reference */
755 if (opc == BC_invokeinterface) {
756 fmi = class_getconstant(be->method->clazz, cp_index, CONSTANT_InterfaceMethodref);
758 fmi = class_getconstant(be->method->clazz, cp_index, CONSTANT_Methodref);
766 md = fmi->parseddesc.md;
770 /* Parse parameters if not done yet. */
772 if (md->params == NULL) {
773 if (! descriptor_params_from_paramtypes(md, opc == BC_invokestatic ? ACC_STATIC : 0)) {
779 /* Try to lazyly resolve method. */
781 result = resolve_method_lazy(be->method, fmi, opc == BC_invokespecial);
783 if (result == resolveSucceeded) {
786 #if BC_ESCAPE_VERBOSE
790 "Succefully resolved callee %s/%s. Recursing.\n",
791 mi->clazz->name->text,
798 #if BC_ESCAPE_VERBOSE
802 "Failed to resolve callee %s/%s.\n",
803 (IS_FMIREF_RESOLVED(fmi) ? "ERR" : fmi->p.classref->name->text),
810 /* If we could resolve the method, either reuse available escape inormation
811 or recurse into callee.
812 Otherwise we must assume, that all parameters escape. */
814 if (mi != NULL && method_profile_is_monomorphic(mi)) {
816 if (mi->paramescape == NULL) {
817 bc_escape_analysis_perform_intern(mi, be->depth + 1);
820 if (mi->paramescape == NULL) {
821 /* No escape information. */
822 bc_escape_analysis_escape_invoke_parameters(be, md);
824 /* Adjust escape state of parameters. */
825 bc_escape_analysis_adjust_invoke_parameters(be, mi);
829 bc_escape_analysis_escape_invoke_parameters(be, md);
833 static void bc_escape_analysis_parse_tableswitch(
834 bc_escape_analysis_t *be,
840 jcode_get_u1(jc); /* opcode */
842 jcode_align_bytecode_index(jc, 4);
844 def = jcode_get_s4(jc);
845 low = jcode_get_s4(jc);
846 high = jcode_get_s4(jc);
849 for (i = 0; i < (high - low + 1); ++i) {
850 bc_escape_analysis_branch_target(
852 jcode_get_branch_target_wide(jc)
859 static void bc_escape_analysis_parse_lookupswitch(
860 bc_escape_analysis_t *be,
866 jcode_get_u1(jc); /* opcode */
868 jcode_align_bytecode_index(jc, 4);
872 bc_escape_analysis_branch_target(
874 jcode_get_branch_target_wide(jc)
879 npairs = jcode_get_s4(jc);
881 for (i = 0; i < npairs; ++i) {
886 bc_escape_analysis_branch_target(
888 jcode_get_branch_target_wide(jc)
894 static void bc_escape_analysis_process_basicblock(bc_escape_analysis_t *be, jcode_t *jc) {
896 op_stack_slot_t value1, value2, value3, value4;
901 #if BC_ESCAPE_VERBOSE
903 dprintf(be->depth, "Processing basicblock at offset %d.\n", jcode_get_index(jc));
907 op_stack_reset(be->stack);
909 /* TODO end if all parameters escape */
910 /* TODO move code into process_instruction or the like */
912 while ((! jcode_end(jc)) && (! bb_end) && (! be->fatal_error)) {
914 jcode_record_instruction_start(jc);
916 opc = jcode_get_u1(jc);
918 length = bytecode[opc].length;
920 #if BC_ESCAPE_VERBOSE
922 dprintf(be->depth, "* %s, ", bytecode[opc].mnemonic);
923 op_stack_print(be->stack, stdout);
943 op_stack_push_unknown(be->stack);
950 op_stack_push_unknown(be->stack);
951 op_stack_push_unknown(be->stack);
956 op_stack_push_unknown(be->stack);
961 op_stack_push_unknown(be->stack);
965 op_stack_push_unknown(be->stack);
966 op_stack_push_unknown(be->stack);
979 op_stack_push_unknown(be->stack);
992 op_stack_push_unknown(be->stack);
993 op_stack_push_unknown(be->stack);
997 op_stack_push(be->stack, bc_escape_analysis_address_local(be, jcode_get_u1(jc)));
1001 op_stack_push(be->stack, bc_escape_analysis_address_local(be, 0));
1005 op_stack_push(be->stack, bc_escape_analysis_address_local(be, 1));
1009 op_stack_push(be->stack, bc_escape_analysis_address_local(be, 2));
1013 op_stack_push(be->stack, bc_escape_analysis_address_local(be, 3));
1021 op_stack_pop(be->stack);
1022 op_stack_pop(be->stack);
1023 op_stack_push_unknown(be->stack);
1028 op_stack_pop(be->stack);
1029 op_stack_pop(be->stack);
1030 op_stack_push_unknown(be->stack);
1031 op_stack_push_unknown(be->stack);
1035 op_stack_pop(be->stack);
1036 op_stack_pop(be->stack);
1037 op_stack_push_unknown(be->stack);
1042 bc_escape_analysis_dirty(be, jcode_get_u1(jc));
1043 op_stack_pop(be->stack);
1048 bc_escape_analysis_dirty(be, 0);
1049 op_stack_pop(be->stack);
1054 bc_escape_analysis_dirty(be, 1);
1055 op_stack_pop(be->stack);
1060 bc_escape_analysis_dirty(be, 2);
1061 op_stack_pop(be->stack);
1066 bc_escape_analysis_dirty(be, 3);
1067 op_stack_pop(be->stack);
1072 bc_escape_analysis_dirty_2(be, jcode_get_u1(jc));
1073 op_stack_pop(be->stack);
1074 op_stack_pop(be->stack);
1079 bc_escape_analysis_dirty_2(be, 0);
1080 op_stack_pop(be->stack);
1081 op_stack_pop(be->stack);
1086 bc_escape_analysis_dirty_2(be, 1);
1087 op_stack_pop(be->stack);
1088 op_stack_pop(be->stack);
1093 bc_escape_analysis_dirty_2(be, 2);
1094 op_stack_pop(be->stack);
1095 op_stack_pop(be->stack);
1100 bc_escape_analysis_dirty_2(be, 3);
1101 op_stack_pop(be->stack);
1102 op_stack_pop(be->stack);
1106 bc_escape_analysis_dirty(be, jcode_get_u1(jc));
1107 bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
1111 bc_escape_analysis_dirty(be, 0);
1112 bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
1116 bc_escape_analysis_dirty(be, 1);
1117 bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
1121 bc_escape_analysis_dirty(be, 2);
1122 bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
1126 bc_escape_analysis_dirty(be, 3);
1127 bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
1135 op_stack_pop(be->stack);
1136 op_stack_pop(be->stack);
1137 op_stack_pop(be->stack);
1142 op_stack_pop(be->stack);
1143 op_stack_pop(be->stack);
1144 op_stack_pop(be->stack);
1145 op_stack_pop(be->stack);
1149 op_stack_pop(be->stack);
1150 op_stack_pop(be->stack);
1151 bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
1155 op_stack_pop(be->stack);
1159 op_stack_pop(be->stack);
1160 op_stack_pop(be->stack);
1164 value1 = op_stack_get(be->stack, 1);
1165 op_stack_push(be->stack, value1);
1169 value1 = op_stack_pop(be->stack);
1170 value2 = op_stack_pop(be->stack);
1171 op_stack_push(be->stack, value1);
1172 op_stack_push(be->stack, value2);
1173 op_stack_push(be->stack, value1);
1177 value1 = op_stack_pop(be->stack);
1178 value2 = op_stack_pop(be->stack);
1179 value3 = op_stack_pop(be->stack);
1180 op_stack_push(be->stack, value1);
1181 op_stack_push(be->stack, value3);
1182 op_stack_push(be->stack, value2);
1183 op_stack_push(be->stack, value1);
1187 value1 = op_stack_get(be->stack, 1);
1188 value2 = op_stack_get(be->stack, 2);
1189 op_stack_push(be->stack, value2);
1190 op_stack_push(be->stack, value1);
1194 value1 = op_stack_pop(be->stack);
1195 value2 = op_stack_pop(be->stack);
1196 value3 = op_stack_pop(be->stack);
1197 op_stack_push(be->stack, value2);
1198 op_stack_push(be->stack, value1);
1199 op_stack_push(be->stack, value3);
1200 op_stack_push(be->stack, value2);
1201 op_stack_push(be->stack, value1);
1205 value1 = op_stack_pop(be->stack);
1206 value2 = op_stack_pop(be->stack);
1207 value3 = op_stack_pop(be->stack);
1208 value4 = op_stack_pop(be->stack);
1209 op_stack_push(be->stack, value2);
1210 op_stack_push(be->stack, value1);
1211 op_stack_push(be->stack, value4);
1212 op_stack_push(be->stack, value3);
1213 op_stack_push(be->stack, value2);
1214 op_stack_push(be->stack, value1);
1218 value1 = op_stack_get(be->stack, 1);
1219 value2 = op_stack_get(be->stack, 2);
1220 op_stack_set(be->stack, 1, value2);
1221 op_stack_set(be->stack, 2, value1);
1239 op_stack_pop(be->stack);
1240 op_stack_pop(be->stack);
1241 op_stack_push_unknown(be->stack);
1259 op_stack_pop(be->stack);
1260 op_stack_pop(be->stack);
1261 op_stack_pop(be->stack);
1262 op_stack_pop(be->stack);
1263 op_stack_push_unknown(be->stack);
1264 op_stack_push_unknown(be->stack);
1278 op_stack_pop(be->stack);
1279 op_stack_pop(be->stack);
1280 op_stack_push_unknown(be->stack);
1286 op_stack_pop(be->stack);
1287 op_stack_pop(be->stack);
1288 /* Second operand is int. */
1289 op_stack_pop(be->stack);
1290 op_stack_push_unknown(be->stack);
1291 op_stack_push_unknown(be->stack);
1297 op_stack_pop(be->stack);
1298 op_stack_pop(be->stack);
1299 op_stack_push_unknown(be->stack);
1305 op_stack_pop(be->stack);
1306 op_stack_pop(be->stack);
1307 op_stack_pop(be->stack);
1308 op_stack_pop(be->stack);
1309 op_stack_push_unknown(be->stack);
1310 op_stack_push_unknown(be->stack);
1314 /* Not stack operation. */
1315 bc_escape_analysis_dirty(be, jcode_get_u1(jc));
1320 op_stack_pop(be->stack);
1321 op_stack_push_unknown(be->stack);
1322 op_stack_push_unknown(be->stack);
1326 op_stack_pop(be->stack);
1327 op_stack_push_unknown(be->stack);
1332 op_stack_pop(be->stack);
1333 op_stack_pop(be->stack);
1334 op_stack_push_unknown(be->stack);
1338 op_stack_pop(be->stack);
1339 op_stack_pop(be->stack);
1340 op_stack_push_unknown(be->stack);
1341 op_stack_push_unknown(be->stack);
1345 op_stack_pop(be->stack);
1346 op_stack_push_unknown(be->stack);
1351 op_stack_pop(be->stack);
1352 op_stack_push_unknown(be->stack);
1353 op_stack_push_unknown(be->stack);
1358 op_stack_pop(be->stack);
1359 op_stack_pop(be->stack);
1360 op_stack_push_unknown(be->stack);
1364 op_stack_pop(be->stack);
1365 op_stack_pop(be->stack);
1366 op_stack_push_unknown(be->stack);
1367 op_stack_push_unknown(be->stack);
1373 op_stack_pop(be->stack);
1374 op_stack_push_unknown(be->stack);
1379 op_stack_pop(be->stack);
1380 op_stack_pop(be->stack);
1381 op_stack_push_unknown(be->stack);
1387 op_stack_pop(be->stack);
1388 op_stack_pop(be->stack);
1389 op_stack_pop(be->stack);
1390 op_stack_pop(be->stack);
1391 op_stack_push_unknown(be->stack);
1400 op_stack_pop(be->stack);
1401 bc_escape_analysis_branch_target(be, jcode_get_branch_target(jc));
1402 bc_escape_analysis_branch_target(be, jcode_get_fall_through_target(jc));
1412 op_stack_pop(be->stack);
1413 op_stack_pop(be->stack);
1414 bc_escape_analysis_branch_target(be, jcode_get_branch_target(jc));
1415 bc_escape_analysis_branch_target(be, jcode_get_fall_through_target(jc));
1421 bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_METHOD);
1422 bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_METHOD);
1423 bc_escape_analysis_branch_target(be, jcode_get_branch_target(jc));
1424 bc_escape_analysis_branch_target(be, jcode_get_fall_through_target(jc));
1429 bc_escape_analysis_branch_target(be, jcode_get_branch_target(jc));
1434 op_stack_push_unknown(be->stack);
1435 bc_escape_analysis_branch_target(be, jcode_get_branch_target(jc));
1442 case BC_tableswitch:
1443 op_stack_pop(be->stack);
1444 jcode_rewind_instruction(jc);
1445 bc_escape_analysis_parse_tableswitch(be, jc);
1446 length = jcode_get_instruction_length(jc);
1450 case BC_lookupswitch:
1451 op_stack_pop(be->stack);
1452 jcode_rewind_instruction(jc);
1453 bc_escape_analysis_parse_lookupswitch(be, jc);
1454 length = jcode_get_instruction_length(jc);
1464 op_stack_pop(be->stack);
1470 op_stack_pop(be->stack);
1471 op_stack_pop(be->stack);
1477 bc_escape_analysis_returned(be, op_stack_pop(be->stack));
1482 op_stack_pop(be->stack);
1487 bc_escape_analysis_value_category(be, jcode_get_s2(jc)) ==
1490 op_stack_push_unknown(be->stack);
1492 op_stack_push_unknown(be->stack);
1498 bc_escape_analysis_value_category(be, jcode_get_u2(jc)) ==
1501 op_stack_pop(be->stack);
1503 op_stack_pop(be->stack);
1504 op_stack_pop(be->stack);
1506 value2 = op_stack_pop(be->stack);
1507 value1 = op_stack_pop(be->stack);
1508 bc_escape_analysis_adjust_state(be, value2, ESCAPE_GLOBAL);
1514 bc_escape_analysis_value_category(be, jcode_get_u2(jc)) ==
1517 op_stack_pop(be->stack);
1518 op_stack_pop(be->stack);
1520 value1 = op_stack_pop(be->stack);
1521 bc_escape_analysis_adjust_state(be, value1, ESCAPE_GLOBAL);
1525 case BC_invokevirtual:
1526 case BC_invokespecial:
1527 case BC_invokestatic:
1528 case BC_invokeinterface:
1529 jcode_rewind_instruction(jc);
1530 bc_escape_analysis_parse_invoke(be, jc);
1534 op_stack_push_unknown(be->stack);
1539 op_stack_pop(be->stack);
1540 op_stack_push_unknown(be->stack);
1543 case BC_arraylength:
1544 bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_METHOD);
1545 op_stack_push_unknown(be->stack);
1549 bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
1554 value1 = op_stack_get(be->stack, 1);
1555 bc_escape_analysis_adjust_state(be, value1, ESCAPE_METHOD);
1559 value1 = op_stack_pop(be->stack);
1560 bc_escape_analysis_adjust_state(be, value1, ESCAPE_METHOD);
1561 op_stack_push_unknown(be->stack);
1564 case BC_monitorenter:
1565 case BC_monitorexit:
1566 value1 = op_stack_pop(be->stack);
1567 bc_escape_analysis_adjust_state(be, value1, ESCAPE_METHOD);
1572 /* All except iinc have a length of 4. */
1575 switch (jcode_get_u1(jc)) {
1578 op_stack_push_unknown(be->stack);
1583 op_stack_push_unknown(be->stack);
1584 op_stack_push_unknown(be->stack);
1590 bc_escape_analysis_address_local(
1599 bc_escape_analysis_dirty(be, jcode_get_u2(jc));
1600 op_stack_pop(be->stack);
1605 bc_escape_analysis_dirty_2(be, jcode_get_u2(jc));
1606 op_stack_pop(be->stack);
1607 op_stack_pop(be->stack);
1611 bc_escape_analysis_dirty(be, jcode_get_u2(jc));
1612 bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
1620 bc_escape_analysis_dirty(be, jcode_get_u2(jc));
1627 case BC_multianewarray:
1629 dim = jcode_get_u1(jc);
1631 op_stack_pop(be->stack);
1633 op_stack_push_unknown(be->stack);
1638 value1 = op_stack_pop(be->stack);
1639 bc_escape_analysis_adjust_state(be, value1, ESCAPE_METHOD);
1640 bc_escape_analysis_branch_target(be, jcode_get_branch_target(jc));
1641 bc_escape_analysis_branch_target(be, jcode_get_fall_through_target(jc));
1646 bc_escape_analysis_branch_target(be, jcode_get_branch_target_wide(jc));
1651 bc_escape_analysis_branch_target(be, jcode_get_branch_target_wide(jc));
1664 jcode_forward_instruction_relative(jc, length);
1666 #if BC_ESCAPE_VERBOSE
1668 op_stack_print(be->stack, stdout);
1674 #if BC_ESCAPE_VERBOSE
1676 dprintf(be->depth, "Elements left on stack: %d\n", op_stack_element_count(be->stack));
1680 while ((! op_stack_is_empty(be->stack)) && (! be->fatal_error)) {
1681 #if BC_ESCAPE_VERBOSE
1683 dprintf(be->depth, "Stack element: ");
1684 op_stack_print(be->stack, stdout);
1688 bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
1689 #if BC_ESCAPE_VERBOSE
1691 op_stack_print(be->stack, stdout);
1697 if (be->fatal_error) {
1698 #if BC_ESCAPE_VERBOSE
1700 printf("Fatal error while processing basic block. Aborting.\n");
1707 static void bc_escape_analysis_adjust_return_value(bc_escape_analysis_t *be) {
1708 escape_state_t re, pe;
1711 /* Only calculate, if return value is of type address. */
1713 if (be->method->parseddesc->returntype.type != TYPE_ADR) {
1717 /* If a parameter can be returned, adjust to its escape state. */
1719 for (i = 0; i < be->param_escape_size; ++i) {
1720 if (bit_vector_get(be->adr_param_returned, i)) {
1721 be->param_escape[i] |= 0x80;
1723 pe = escape_state_from_u1(be->param_escape[i]);
1724 re = escape_state_from_u1(be->param_escape[-1]);
1727 be->param_escape[-1] = escape_state_to_u1(pe);
1733 static void bc_escape_analysis_analyze(bc_escape_analysis_t *be) {
1734 raw_exception_entry *itee;
1735 basicblock_work_item_t *bb;
1738 /* Add root as basic block. */
1740 bc_escape_analysis_branch_target(be, 0);
1742 /* Add each exception handler as basic block. */
1745 itee = be->method->rawexceptiontable;
1746 itee != be->method->rawexceptiontable + be->method->rawexceptiontablelength;
1749 bc_escape_analysis_branch_target(be, itee->handlerpc);
1752 /* Init jcode parser. */
1757 be->method->jcodelength,
1762 /* Process basicblock by basicblock. */
1764 for (bb = be->basicblocks->first; bb; bb = bb->next) {
1765 jcode_move_to_index(&jc, bb->bytecode_index);
1766 bc_escape_analysis_process_basicblock(
1772 /* Calculate escape of return value. */
1774 bc_escape_analysis_adjust_return_value(be);
1776 /* Export escape of parameters. */
1778 be->method->paramescape = be->param_escape;
1781 static void bc_escape_analysis_perform_intern(methodinfo *m, int depth) {
1782 bc_escape_analysis_t *be;
1783 bool verbose = false;
1785 #if BC_ESCAPE_VERBOSE
1789 "=== BC escape analysis of %s/%s at depth %d ===\n",
1790 m->clazz->name->text,
1797 if (m->paramescape != NULL) {
1798 #if BC_ESCAPE_VERBOSE
1800 dprintf(depth, "Escape info for method already available.\n");
1806 if ((m->flags & ACC_METHOD_EA) != 0) {
1807 #if BC_ESCAPE_VERBOSE
1809 dprintf(depth, "Detected recursion, aborting.\n");
1815 if (m->jcode == NULL) {
1816 #if BC_ESCAPE_VERBOSE
1818 dprintf(depth, "No bytecode for callee.\n");
1824 /* TODO threshold */
1826 be = DNEW(bc_escape_analysis_t);
1827 bc_escape_analysis_init(be, m, verbose, depth);
1829 m->flags |= ACC_METHOD_EA;
1831 bc_escape_analysis_analyze(be);
1833 #if BC_ESCAPE_VERBOSE
1837 "%s/%s: Non-escaping params: %d\n",
1838 m->clazz->name->text,
1840 be->non_escaping_adr_params
1845 m->flags &= ~ACC_METHOD_EA;
1848 void bc_escape_analysis_perform(methodinfo *m) {
1849 bc_escape_analysis_perform_intern(m, 0);