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;
123 #define stack_assert_position(stack, pos) \
125 assert((stack)->elements <= (pos)); \
126 assert((pos) < (stack)->end); \
129 static void op_stack_init(op_stack_t *stack, unsigned max) {
132 stack->elements = DMNEW(op_stack_slot_t, max * 2);
134 stack->start = stack->elements + max;
135 stack->end = stack->elements + max + max;
137 for (it = stack->elements; it != stack->start; ++it) {
138 *it = OP_STACK_SLOT_UNKNOWN;
141 stack->ptr = stack->start;
142 stack->bottom = stack->start;
145 static void op_stack_reset(op_stack_t *stack) {
148 /* Clear bottom half. */
150 for (it = stack->bottom; it != stack->elements + stack->max; ++it) {
151 *it = OP_STACK_SLOT_UNKNOWN;
154 /* Reset pointers. */
156 stack->ptr = stack->start;
157 stack->bottom = stack->start;
160 static op_stack_slot_t op_stack_pop(op_stack_t *stack) {
163 stack_assert_position(stack, stack->ptr);
165 if (stack->ptr < stack->bottom) {
166 stack->bottom = stack->ptr;
171 static void op_stack_push(op_stack_t *stack, op_stack_slot_t element) {
172 stack_assert_position(stack, stack->ptr);
173 *(stack->ptr) = element;
177 static op_stack_slot_t op_stack_get(const op_stack_t *stack, int offset) {
178 stack_assert_position(stack, stack->ptr - offset);
179 return *(stack->ptr - offset);
182 static void op_stack_set(op_stack_t *stack, int offset, op_stack_slot_t value) {
183 stack_assert_position(stack, stack->ptr - offset);
184 *(stack->ptr - offset) = value;
187 static inline void op_stack_push_unknown(op_stack_t *stack) {
188 op_stack_push(stack, OP_STACK_SLOT_UNKNOWN);
191 static void op_stack_print(const op_stack_t *stack, FILE *f) {
195 for (it = stack->bottom; it < stack->ptr; ++it) {
196 if (it == stack->start) {
201 if (op_stack_slot_is_unknown(*it)) {
202 fprintf(f, "%c----", sep);
204 fprintf(f, "%cP%3d", sep, it->index);
211 static bool op_stack_is_empty(const op_stack_t *stack) {
212 return !(stack->bottom < stack->ptr);
215 static s4 op_stack_element_count(const op_stack_t *stack) {
216 return (stack->ptr - stack->bottom);
219 /*** bit_vector **************************************************************/
226 static void bit_vector_init(bit_vector_t *bv, s4 size) {
227 bv->bv = bv_new(size);
231 static s4 bit_vector_size(const bit_vector_t *bv) {
235 static void bit_vector_set(bit_vector_t *bv, s4 bit) {
236 assert(0 <= bit && bit < bv->size);
237 bv_set_bit(bv->bv, bit);
240 static bool bit_vector_get(const bit_vector_t *bv, s4 bit) {
241 assert(0 <= bit && bit < bv->size);
242 return bv_get_bit(bv->bv, bit);
245 /*** basicblock_work_list ***********************************************/
247 typedef struct basicblock_work_item {
249 struct basicblock_work_item *next;
250 } basicblock_work_item_t;
253 basicblock_work_item_t *first;
254 basicblock_work_item_t *last;
255 } basicblock_work_list_t;
257 void basicblock_work_list_init(basicblock_work_list_t *lst) {
262 #define FOR_EACH_BASICBLOCK_WORK_LIST(lst, it) \
263 for ((it) = (lst)->first; (it); (it) = (it)->next)
265 void basicblock_work_list_insert(basicblock_work_list_t *lst, s4 bytecode_index) {
266 basicblock_work_item_t *it, *item;
268 /* If the destination is already present in the list, do nothing. */
270 FOR_EACH_BASICBLOCK_WORK_LIST(lst, it) {
271 if (it->bytecode_index == bytecode_index) {
276 item = DNEW(basicblock_work_item_t);
277 item->bytecode_index = bytecode_index;
280 if (lst->first == NULL) {
284 lst->last->next = item;
289 /*** value_category *****************************************************/
296 /*** jcode **************************************************************/
302 u1 *instruction_start;
306 static void jcode_init(jcode_t *jc, u1 *start, s4 length, s4 offset) {
308 jc->end = jc->start + length;
313 static void jcode_move_to_index(jcode_t *jc, s4 index) {
314 jc->pos = jc->start + (index - jc->offset);
317 static bool jcode_end(const jcode_t *jc) {
318 return (jc->pos >= jc->end);
321 static void jcode_record_instruction_start(jcode_t *jc) {
322 jc->instruction_start = jc->pos;
325 static void jcode_rewind_instruction(jcode_t *jc) {
326 jc->pos = jc->instruction_start;
329 static s4 jcode_get_instruction_length(const jcode_t *jc) {
330 return (jc->pos - jc->instruction_start);
333 static void jcode_align_bytecode_index(jcode_t *jc, s4 align) {
336 idx = jc->offset + (jc->pos - jc->start);
337 aidx = MEMORY_ALIGN(idx, align);
339 jc->pos += (aidx - idx);
342 static void jcode_forward_instruction_relative(jcode_t *jc, s4 n) {
343 jc->pos = jc->instruction_start + n;
346 static s4 jcode_get_index(const jcode_t *jc) {
347 return jc->offset + (jc->pos - jc->start);
350 #define jcode_assert_has_bytes(jc, n) \
351 assert((jc->pos + n) <= jc->end)
353 static u1 jcode_get_u1(jcode_t *jc) {
355 jcode_assert_has_bytes(jc, 1);
361 static s2 jcode_get_s2(jcode_t *jc) {
363 jcode_assert_has_bytes(jc, 2);
364 ret = (jc->pos[0] << 8) | (jc->pos[1]);
369 static u2 jcode_get_u2(jcode_t *jc) {
371 jcode_assert_has_bytes(jc, 2);
372 ret = (jc->pos[0] << 8) | (jc->pos[1]);
377 static s4 jcode_get_s4(jcode_t *jc) {
379 jcode_assert_has_bytes(jc, 4);
380 ret = (jc->pos[0] << 24) | (jc->pos[1] << 16) | (jc->pos[2] << 8) | (jc->pos[3]);
385 static s4 jcode_get_branch_target(jcode_t *jc) {
386 s2 off = jcode_get_s2(jc);
387 return jc->offset + (jc->instruction_start - jc->start) + off;
390 static s4 jcode_get_branch_target_wide(jcode_t *jc) {
391 s4 off = jcode_get_s4(jc);
392 return jc->offset + (jc->instruction_start - jc->start) + off;
395 static s4 jcode_get_fall_through_target(jcode_t *jc) {
396 int length = bytecode[*jc->instruction_start].length;
398 return jc->offset + (jc->instruction_start - jc->start) + length;
401 /*** bc_escape_analysis *************************************************/
406 basicblock_work_list_t *basicblocks;
408 op_stack_slot_t *local_to_adr_param;
409 s4 local_to_adr_param_size;
412 s4 param_escape_size;
414 bit_vector_t *adr_param_dirty;
415 bit_vector_t *adr_param_returned;
417 s4 non_escaping_adr_params;
419 #if BC_ESCAPE_VERBOSE
423 } bc_escape_analysis_t;
425 static void bc_escape_analysis_perform_intern(methodinfo *m, int depth);
427 static void bc_escape_analysis_init(bc_escape_analysis_t *be, methodinfo *m, bool verbose, int depth) {
438 be->stack = DNEW(op_stack_t);
439 op_stack_init(be->stack, m->maxstack);
441 be->basicblocks = DNEW(basicblock_work_list_t);
442 basicblock_work_list_init(be->basicblocks);
444 be->local_to_adr_param_size = m->parseddesc->paramslots;
445 be->local_to_adr_param = DMNEW(op_stack_slot_t, m->parseddesc->paramslots);
447 /* Count number of address parameters a. */
449 for (p = 0, l = 0, a = 0; p < m->parseddesc->paramcount; ++p) {
450 t = m->parseddesc->paramtypes[p].type;
452 be->local_to_adr_param[l] = op_stack_slot_create_param(a);
455 } else if (IS_2_WORD_TYPE(t)) {
456 be->local_to_adr_param[l] = OP_STACK_SLOT_UNKNOWN;
457 be->local_to_adr_param[l + 1] = OP_STACK_SLOT_UNKNOWN;
460 be->local_to_adr_param[l] = OP_STACK_SLOT_UNKNOWN;
465 assert(l == be->local_to_adr_param_size);
467 /* Determine whether return type is address */
469 ret_adr = m->parseddesc->returntype.type == TYPE_ADR ? 1 : 0;
471 /* Allocate param_escape on heap. */
473 be->param_escape_size = a;
477 /* Use some non-NULL value. */
478 be->param_escape = (u1 *)1;
480 be->param_escape = MNEW(u1, n);
483 for (ite = be->param_escape; ite != be->param_escape + n; ++ite) {
484 *ite = (u1)ESCAPE_NONE;
487 be->param_escape += ret_adr;
489 be->adr_param_dirty = DNEW(bit_vector_t);
490 bit_vector_init(be->adr_param_dirty, a);
492 be->adr_param_returned= DNEW(bit_vector_t);
493 bit_vector_init(be->adr_param_returned, a);
495 be->non_escaping_adr_params = be->param_escape_size;
497 #if BC_ESCAPE_VERBOSE
498 be->verbose = verbose;
504 static void bc_escape_analysis_branch_target(bc_escape_analysis_t *be, s4 branch_target) {
505 basicblock_work_list_insert(be->basicblocks, branch_target);
508 static void bc_escape_analysis_adjust_state(
509 bc_escape_analysis_t *be,
510 op_stack_slot_t adr_param,
511 escape_state_t escape_state
515 if (op_stack_slot_is_param(adr_param)) {
516 if (0 <= adr_param.index && adr_param.index < be->param_escape_size) {
517 old = (escape_state_t)be->param_escape[adr_param.index];
518 if (old < escape_state) {
520 /* Adjust escape state. */
521 be->param_escape[adr_param.index] = (u1)escape_state;
523 /* If the parameter has just escaped, decrement number of non-escaping
527 old < ESCAPE_GLOBAL_THROUGH_METHOD &&
528 escape_state >= ESCAPE_GLOBAL_THROUGH_METHOD
530 be->non_escaping_adr_params -= 1;
537 static void bc_escape_analysis_dirty(bc_escape_analysis_t *be, s4 local) {
538 op_stack_slot_t adr_param;
540 if (0 <= local && local < be->local_to_adr_param_size) {
541 adr_param = be->local_to_adr_param[local];
542 if (op_stack_slot_is_param(adr_param)) {
543 bit_vector_set(be->adr_param_dirty, adr_param.index);
548 static void bc_escape_analysis_dirty_2(bc_escape_analysis_t *be, s4 local) {
549 bc_escape_analysis_dirty(be, local);
550 bc_escape_analysis_dirty(be, local + 1);
553 static void bc_escape_analyisis_returned(bc_escape_analysis_t *be, op_stack_slot_t value) {
554 if (op_stack_slot_is_param(value)) {
555 /* A parameter is returned, mark it as being returned. */
556 bit_vector_set(be->adr_param_returned, value.index);
557 } else if (op_stack_slot_is_unknown(value)) {
558 /* An untracked value is returned.
559 Conservatively asume a globally escaping value is returned. */
560 if (be->method->parseddesc->returntype.type == TYPE_ADR) {
561 be->param_escape[-1] = (u1)ESCAPE_GLOBAL;
566 op_stack_slot_t bc_escape_analysis_address_local(bc_escape_analysis_t *be, s4 local) {
567 if (0 <= local && local < be->local_to_adr_param_size) {
568 return be->local_to_adr_param[local];
570 return OP_STACK_SLOT_UNKNOWN;
574 value_category_t bc_escape_analysis_value_category(bc_escape_analysis_t *be, s4 index) {
575 constant_FMIref *fmi;
576 fmi = class_getconstant(be->method->clazz, index, CONSTANT_Fieldref);
583 switch (fmi->parseddesc.fd->type) {
586 return VALUE_CATEGORY_2;
588 return VALUE_CATEGORY_1;
592 static void bc_escape_analysis_adjust_invoke_parameters(
593 bc_escape_analysis_t *be,
597 methoddesc *md = mi->parseddesc;
598 u1 *paramescape = mi->paramescape;
599 s4 stack_depth = md->paramslots;
601 /* Process parameters.
602 * The first parameter is at the highest depth on the stack.
605 for (i = 0; i < md->paramcount; ++i) {
606 switch (md->paramtypes[i].type) {
608 bc_escape_analysis_adjust_state(
610 op_stack_get(be->stack, stack_depth),
611 (escape_state_t)*(paramescape++)
625 /* Pop all parameters. */
627 for (i = 0; i < md->paramslots; ++i) {
628 op_stack_pop(be->stack);
633 static void bc_escape_analysis_escape_invoke_parameters(
634 bc_escape_analysis_t *be,
638 for (i = 0; i < md->paramslots; ++i) {
639 bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
643 static void bc_escape_analysis_parse_invoke(bc_escape_analysis_t *be, jcode_t *jc) {
644 constant_FMIref *fmi;
649 resolve_result_t result;
652 opc = jcode_get_u1(jc);
653 cp_index = jcode_get_u2(jc);
655 /* Get method reference */
657 if (opc == BC_invokeinterface) {
658 fmi = class_getconstant(be->method->clazz, cp_index, CONSTANT_InterfaceMethodref);
660 fmi = class_getconstant(be->method->clazz, cp_index, CONSTANT_Methodref);
668 md = fmi->parseddesc.md;
672 /* Parse parameters if not done yet. */
674 if (md->params == NULL) {
675 if (! descriptor_params_from_paramtypes(md, opc == BC_invokestatic ? ACC_STATIC : 0)) {
681 /* Try to lazyly resolve method. */
683 result = resolve_method_lazy(be->method, fmi, opc == BC_invokespecial);
685 if (result == resolveSucceeded) {
688 #if BC_ESCAPE_VERBOSE
692 "Succefully resolved callee %s/%s. Recursing.\n",
693 mi->clazz->name->text,
700 #if BC_ESCAPE_VERBOSE
704 "Failed to resolve callee %s/%s.\n",
705 (IS_FMIREF_RESOLVED(fmi) ? "ERR" : fmi->p.classref->name->text),
712 /* If we could resolve the method, either reuse available escape inormation
713 or recurse into callee.
714 Otherwise we must assume, that all parameters escape. */
718 if (mi->paramescape == NULL) {
719 bc_escape_analysis_perform_intern(mi, be->depth + 1);
722 if (mi->paramescape == NULL) {
723 /* No escape information. */
724 bc_escape_analysis_escape_invoke_parameters(be, md);
726 /* Adjust escape state of parameters. */
727 bc_escape_analysis_adjust_invoke_parameters(be, mi);
731 bc_escape_analysis_escape_invoke_parameters(be, md);
734 switch (md->returntype.type) {
737 op_stack_push_unknown(be->stack);
738 op_stack_push_unknown(be->stack);
744 op_stack_push_unknown(be->stack);
749 static void bc_escape_analysis_parse_tableswitch(
750 bc_escape_analysis_t *be,
756 jcode_get_u1(jc); /* opcode */
758 jcode_align_bytecode_index(jc, 4);
760 def = jcode_get_s4(jc);
761 low = jcode_get_s4(jc);
762 high = jcode_get_s4(jc);
765 for (i = 0; i < (high - low + 1); ++i) {
766 bc_escape_analysis_branch_target(
768 jcode_get_branch_target_wide(jc)
775 static void bc_escape_analysis_parse_lookupswitch(
776 bc_escape_analysis_t *be,
782 jcode_get_u1(jc); /* opcode */
784 jcode_align_bytecode_index(jc, 4);
788 bc_escape_analysis_branch_target(
790 jcode_get_branch_target_wide(jc)
795 npairs = jcode_get_s4(jc);
797 for (i = 0; i < npairs; ++i) {
802 bc_escape_analysis_branch_target(
804 jcode_get_branch_target_wide(jc)
810 static void bc_escape_analysis_process_basicblock(bc_escape_analysis_t *be, jcode_t *jc) {
812 op_stack_slot_t value1, value2, value3, value4;
817 #if BC_ESCAPE_VERBOSE
819 dprintf(be->depth, "Processing basicblock at offset %d.\n", jcode_get_index(jc));
823 op_stack_reset(be->stack);
825 /* TODO end if all parameters escape */
826 /* TODO move code into process_instruction or the like */
828 while ((! jcode_end(jc)) && (! bb_end)) {
830 jcode_record_instruction_start(jc);
832 opc = jcode_get_u1(jc);
834 length = bytecode[opc].length;
836 #if BC_ESCAPE_VERBOSE
838 dprintf(be->depth, "* %s, ", bytecode[opc].mnemonic);
839 op_stack_print(be->stack, stdout);
859 op_stack_push_unknown(be->stack);
866 op_stack_push_unknown(be->stack);
867 op_stack_push_unknown(be->stack);
872 op_stack_push_unknown(be->stack);
877 op_stack_push_unknown(be->stack);
881 op_stack_push_unknown(be->stack);
882 op_stack_push_unknown(be->stack);
895 op_stack_push_unknown(be->stack);
908 op_stack_push_unknown(be->stack);
909 op_stack_push_unknown(be->stack);
913 op_stack_push(be->stack, bc_escape_analysis_address_local(be, jcode_get_u1(jc)));
917 op_stack_push(be->stack, bc_escape_analysis_address_local(be, 0));
921 op_stack_push(be->stack, bc_escape_analysis_address_local(be, 1));
925 op_stack_push(be->stack, bc_escape_analysis_address_local(be, 2));
929 op_stack_push(be->stack, bc_escape_analysis_address_local(be, 3));
937 op_stack_pop(be->stack);
938 op_stack_pop(be->stack);
939 op_stack_push_unknown(be->stack);
944 op_stack_pop(be->stack);
945 op_stack_pop(be->stack);
946 op_stack_push_unknown(be->stack);
947 op_stack_push_unknown(be->stack);
951 op_stack_pop(be->stack);
952 op_stack_pop(be->stack);
953 op_stack_push_unknown(be->stack);
958 bc_escape_analysis_dirty(be, jcode_get_u1(jc));
959 op_stack_pop(be->stack);
964 bc_escape_analysis_dirty(be, 0);
965 op_stack_pop(be->stack);
970 bc_escape_analysis_dirty(be, 1);
971 op_stack_pop(be->stack);
976 bc_escape_analysis_dirty(be, 2);
977 op_stack_pop(be->stack);
982 bc_escape_analysis_dirty(be, 3);
983 op_stack_pop(be->stack);
988 bc_escape_analysis_dirty_2(be, jcode_get_u1(jc));
989 op_stack_pop(be->stack);
990 op_stack_pop(be->stack);
995 bc_escape_analysis_dirty_2(be, 0);
996 op_stack_pop(be->stack);
997 op_stack_pop(be->stack);
1002 bc_escape_analysis_dirty_2(be, 1);
1003 op_stack_pop(be->stack);
1004 op_stack_pop(be->stack);
1009 bc_escape_analysis_dirty_2(be, 2);
1010 op_stack_pop(be->stack);
1011 op_stack_pop(be->stack);
1016 bc_escape_analysis_dirty_2(be, 3);
1017 op_stack_pop(be->stack);
1018 op_stack_pop(be->stack);
1022 bc_escape_analysis_dirty(be, jcode_get_u1(jc));
1023 bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
1027 bc_escape_analysis_dirty(be, 0);
1028 bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
1032 bc_escape_analysis_dirty(be, 1);
1033 bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
1037 bc_escape_analysis_dirty(be, 2);
1038 bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
1042 bc_escape_analysis_dirty(be, 3);
1043 bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
1051 op_stack_pop(be->stack);
1052 op_stack_pop(be->stack);
1053 op_stack_pop(be->stack);
1058 op_stack_pop(be->stack);
1059 op_stack_pop(be->stack);
1060 op_stack_pop(be->stack);
1061 op_stack_pop(be->stack);
1065 op_stack_pop(be->stack);
1066 op_stack_pop(be->stack);
1067 bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
1071 op_stack_pop(be->stack);
1075 op_stack_pop(be->stack);
1076 op_stack_pop(be->stack);
1080 value1 = op_stack_get(be->stack, 1);
1081 op_stack_push(be->stack, value1);
1085 value1 = op_stack_pop(be->stack);
1086 value2 = op_stack_pop(be->stack);
1087 op_stack_push(be->stack, value1);
1088 op_stack_push(be->stack, value2);
1089 op_stack_push(be->stack, value1);
1093 value1 = op_stack_pop(be->stack);
1094 value2 = op_stack_pop(be->stack);
1095 value3 = op_stack_pop(be->stack);
1096 op_stack_push(be->stack, value1);
1097 op_stack_push(be->stack, value3);
1098 op_stack_push(be->stack, value2);
1099 op_stack_push(be->stack, value1);
1103 value1 = op_stack_get(be->stack, 1);
1104 value2 = op_stack_get(be->stack, 2);
1105 op_stack_push(be->stack, value2);
1106 op_stack_push(be->stack, value1);
1110 value1 = op_stack_pop(be->stack);
1111 value2 = op_stack_pop(be->stack);
1112 value3 = op_stack_pop(be->stack);
1113 op_stack_push(be->stack, value2);
1114 op_stack_push(be->stack, value1);
1115 op_stack_push(be->stack, value3);
1116 op_stack_push(be->stack, value2);
1117 op_stack_push(be->stack, value1);
1121 value1 = op_stack_pop(be->stack);
1122 value2 = op_stack_pop(be->stack);
1123 value3 = op_stack_pop(be->stack);
1124 value4 = op_stack_pop(be->stack);
1125 op_stack_push(be->stack, value2);
1126 op_stack_push(be->stack, value1);
1127 op_stack_push(be->stack, value4);
1128 op_stack_push(be->stack, value3);
1129 op_stack_push(be->stack, value2);
1130 op_stack_push(be->stack, value1);
1134 value1 = op_stack_get(be->stack, 1);
1135 value2 = op_stack_get(be->stack, 2);
1136 op_stack_set(be->stack, 1, value2);
1137 op_stack_set(be->stack, 2, value1);
1155 op_stack_pop(be->stack);
1156 op_stack_pop(be->stack);
1157 op_stack_push_unknown(be->stack);
1175 op_stack_pop(be->stack);
1176 op_stack_pop(be->stack);
1177 op_stack_pop(be->stack);
1178 op_stack_pop(be->stack);
1179 op_stack_push_unknown(be->stack);
1180 op_stack_push_unknown(be->stack);
1194 op_stack_pop(be->stack);
1195 op_stack_pop(be->stack);
1196 op_stack_push_unknown(be->stack);
1202 op_stack_pop(be->stack);
1203 op_stack_pop(be->stack);
1204 /* Second operand is int. */
1205 op_stack_pop(be->stack);
1206 op_stack_push_unknown(be->stack);
1207 op_stack_push_unknown(be->stack);
1213 op_stack_pop(be->stack);
1214 op_stack_pop(be->stack);
1215 op_stack_push_unknown(be->stack);
1221 op_stack_pop(be->stack);
1222 op_stack_pop(be->stack);
1223 op_stack_pop(be->stack);
1224 op_stack_pop(be->stack);
1225 op_stack_push_unknown(be->stack);
1226 op_stack_push_unknown(be->stack);
1230 /* Not stack operation. */
1231 bc_escape_analysis_dirty(be, jcode_get_u1(jc));
1236 op_stack_pop(be->stack);
1237 op_stack_push_unknown(be->stack);
1238 op_stack_push_unknown(be->stack);
1242 op_stack_pop(be->stack);
1243 op_stack_push_unknown(be->stack);
1248 op_stack_pop(be->stack);
1249 op_stack_pop(be->stack);
1250 op_stack_push_unknown(be->stack);
1254 op_stack_pop(be->stack);
1255 op_stack_pop(be->stack);
1256 op_stack_push_unknown(be->stack);
1257 op_stack_push_unknown(be->stack);
1261 op_stack_pop(be->stack);
1262 op_stack_push_unknown(be->stack);
1267 op_stack_pop(be->stack);
1268 op_stack_push_unknown(be->stack);
1269 op_stack_push_unknown(be->stack);
1274 op_stack_pop(be->stack);
1275 op_stack_pop(be->stack);
1276 op_stack_push_unknown(be->stack);
1280 op_stack_pop(be->stack);
1281 op_stack_pop(be->stack);
1282 op_stack_push_unknown(be->stack);
1283 op_stack_push_unknown(be->stack);
1289 op_stack_pop(be->stack);
1290 op_stack_push_unknown(be->stack);
1295 op_stack_pop(be->stack);
1296 op_stack_pop(be->stack);
1297 op_stack_push_unknown(be->stack);
1303 op_stack_pop(be->stack);
1304 op_stack_pop(be->stack);
1305 op_stack_pop(be->stack);
1306 op_stack_pop(be->stack);
1307 op_stack_push_unknown(be->stack);
1316 op_stack_pop(be->stack);
1317 bc_escape_analysis_branch_target(be, jcode_get_branch_target(jc));
1318 bc_escape_analysis_branch_target(be, jcode_get_fall_through_target(jc));
1328 op_stack_pop(be->stack);
1329 op_stack_pop(be->stack);
1330 bc_escape_analysis_branch_target(be, jcode_get_branch_target(jc));
1331 bc_escape_analysis_branch_target(be, jcode_get_fall_through_target(jc));
1337 bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_METHOD);
1338 bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_METHOD);
1339 bc_escape_analysis_branch_target(be, jcode_get_branch_target(jc));
1340 bc_escape_analysis_branch_target(be, jcode_get_fall_through_target(jc));
1345 bc_escape_analysis_branch_target(be, jcode_get_branch_target(jc));
1350 op_stack_push_unknown(be->stack);
1351 bc_escape_analysis_branch_target(be, jcode_get_branch_target(jc));
1358 case BC_tableswitch:
1359 op_stack_pop(be->stack);
1360 jcode_rewind_instruction(jc);
1361 bc_escape_analysis_parse_tableswitch(be, jc);
1362 length = jcode_get_instruction_length(jc);
1366 case BC_lookupswitch:
1367 op_stack_pop(be->stack);
1368 jcode_rewind_instruction(jc);
1369 bc_escape_analysis_parse_lookupswitch(be, jc);
1370 length = jcode_get_instruction_length(jc);
1380 op_stack_pop(be->stack);
1386 op_stack_pop(be->stack);
1387 op_stack_pop(be->stack);
1393 bc_escape_analyisis_returned(be, op_stack_pop(be->stack));
1398 op_stack_pop(be->stack);
1403 bc_escape_analysis_value_category(be, jcode_get_s2(jc)) ==
1406 op_stack_push_unknown(be->stack);
1408 op_stack_push_unknown(be->stack);
1414 bc_escape_analysis_value_category(be, jcode_get_u2(jc)) ==
1417 op_stack_pop(be->stack);
1419 op_stack_pop(be->stack);
1420 op_stack_pop(be->stack);
1422 value2 = op_stack_pop(be->stack);
1423 value1 = op_stack_pop(be->stack);
1424 bc_escape_analysis_adjust_state(be, value2, ESCAPE_GLOBAL);
1430 bc_escape_analysis_value_category(be, jcode_get_u2(jc)) ==
1433 op_stack_pop(be->stack);
1434 op_stack_pop(be->stack);
1436 value1 = op_stack_pop(be->stack);
1437 bc_escape_analysis_adjust_state(be, value1, ESCAPE_GLOBAL);
1441 case BC_invokevirtual:
1442 case BC_invokespecial:
1443 case BC_invokestatic:
1444 case BC_invokeinterface:
1445 jcode_rewind_instruction(jc);
1446 bc_escape_analysis_parse_invoke(be, jc);
1450 op_stack_push_unknown(be->stack);
1455 op_stack_pop(be->stack);
1456 op_stack_push_unknown(be->stack);
1459 case BC_arraylength:
1460 bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_METHOD);
1461 op_stack_push_unknown(be->stack);
1465 bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
1470 value1 = op_stack_get(be->stack, 1);
1471 bc_escape_analysis_adjust_state(be, value1, ESCAPE_METHOD);
1475 value1 = op_stack_pop(be->stack);
1476 bc_escape_analysis_adjust_state(be, value1, ESCAPE_METHOD);
1477 op_stack_push_unknown(be->stack);
1480 case BC_monitorenter:
1481 case BC_monitorexit:
1482 value1 = op_stack_pop(be->stack);
1483 bc_escape_analysis_adjust_state(be, value1, ESCAPE_METHOD);
1488 /* All except iinc have a length of 4. */
1491 switch (jcode_get_u1(jc)) {
1494 op_stack_push_unknown(be->stack);
1499 op_stack_push_unknown(be->stack);
1500 op_stack_push_unknown(be->stack);
1506 bc_escape_analysis_address_local(
1515 bc_escape_analysis_dirty(be, jcode_get_u2(jc));
1516 op_stack_pop(be->stack);
1521 bc_escape_analysis_dirty_2(be, jcode_get_u2(jc));
1522 op_stack_pop(be->stack);
1523 op_stack_pop(be->stack);
1527 bc_escape_analysis_dirty(be, jcode_get_u2(jc));
1528 bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
1536 bc_escape_analysis_dirty(be, jcode_get_u2(jc));
1543 case BC_multianewarray:
1545 dim = jcode_get_u1(jc);
1547 op_stack_pop(be->stack);
1549 op_stack_push_unknown(be->stack);
1554 value1 = op_stack_pop(be->stack);
1555 bc_escape_analysis_adjust_state(be, value1, ESCAPE_METHOD);
1556 bc_escape_analysis_branch_target(be, jcode_get_branch_target(jc));
1557 bc_escape_analysis_branch_target(be, jcode_get_fall_through_target(jc));
1562 bc_escape_analysis_branch_target(be, jcode_get_branch_target_wide(jc));
1567 bc_escape_analysis_branch_target(be, jcode_get_branch_target_wide(jc));
1580 jcode_forward_instruction_relative(jc, length);
1582 #if BC_ESCAPE_VERBOSE
1584 op_stack_print(be->stack, stdout);
1590 #if BC_ESCAPE_VERBOSE
1592 dprintf(be->depth, "Elements left on stack: %d\n", op_stack_element_count(be->stack));
1596 while (! op_stack_is_empty(be->stack)) {
1597 #if BC_ESCAPE_VERBOSE
1599 dprintf(be->depth, "Stack element: ");
1600 op_stack_print(be->stack, stdout);
1604 bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
1605 #if BC_ESCAPE_VERBOSE
1607 op_stack_print(be->stack, stdout);
1614 static void bc_escape_analysis_adjust_return_value(bc_escape_analysis_t *be) {
1615 escape_state_t e, pe;
1618 /* Only calculate, if return value is of type address. */
1620 if (be->method->parseddesc->returntype.type != TYPE_ADR) {
1624 /* Get current escape state of return value. */
1626 e = (escape_state_t)be->param_escape[-1];
1628 /* If a parameter can be returned, adjust to its escape state. */
1630 for (i = 0; i < be->param_escape_size; ++i) {
1631 if (bit_vector_get(be->adr_param_returned, i)) {
1632 pe = (escape_state_t)be->param_escape[i];
1639 be->param_escape[-1] = (u1)e;
1642 static void bc_escape_analysis_analyze(bc_escape_analysis_t *be) {
1643 raw_exception_entry *itee;
1644 basicblock_work_item_t *bb;
1647 /* Add root as basic block. */
1649 bc_escape_analysis_branch_target(be, 0);
1651 /* Add each exception handler as basic block. */
1654 itee = be->method->rawexceptiontable;
1655 itee != be->method->rawexceptiontable + be->method->rawexceptiontablelength;
1658 bc_escape_analysis_branch_target(be, itee->handlerpc);
1661 /* Init jcode parser. */
1666 be->method->jcodelength,
1670 /* Process basicblock by basicblock. */
1672 for (bb = be->basicblocks->first; bb; bb = bb->next) {
1673 jcode_move_to_index(&jc, bb->bytecode_index);
1674 bc_escape_analysis_process_basicblock(
1680 /* Calculate escape of return value. */
1682 bc_escape_analysis_adjust_return_value(be);
1684 /* Export escape of parameters. */
1686 be->method->paramescape = be->param_escape;
1689 static void bc_escape_analysis_perform_intern(methodinfo *m, int depth) {
1690 bc_escape_analysis_t *be;
1691 bool verbose = false;
1693 #if BC_ESCAPE_VERBOSE
1697 "=== BC escape analysis of %s/%s at depth %d ===\n",
1698 m->clazz->name->text,
1705 if (m->paramescape != NULL) {
1706 #if BC_ESCAPE_VERBOSE
1708 dprintf(depth, "Escape info for method already available.\n");
1714 if ((m->flags & ACC_METHOD_EA) != 0) {
1715 #if BC_ESCAPE_VERBOSE
1717 dprintf(depth, "Detected recursion, aborting.\n");
1723 if (m->jcode == NULL) {
1724 #if BC_ESCAPE_VERBOSE
1726 dprintf(depth, "No bytecode for callee.\n");
1732 /* TODO threshold */
1734 be = DNEW(bc_escape_analysis_t);
1735 bc_escape_analysis_init(be, m, verbose, depth);
1737 m->flags |= ACC_METHOD_EA;
1739 bc_escape_analysis_analyze(be);
1741 #if BC_ESCAPE_VERBOSE
1745 "%s/%s: Non-escaping params: %d\n",
1746 m->clazz->name->text,
1748 be->non_escaping_adr_params
1753 m->flags &= ~ACC_METHOD_EA;
1756 void bc_escape_analysis_perform(methodinfo *m) {
1757 bc_escape_analysis_perform_intern(m, 0);