Logo Search packages:      
Sourcecode: cacao-source version File versions  Download package

bytecode_escape.c

/* src/vm/optimizing/bytecode_escape.c

   Copyright (C) 2008
   CACAOVM - Verein zu Foerderung der freien virtuellen Machine CACAO

   This file is part of CACAO.

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2, or (at
   your option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
   02110-1301, USA.
*/

#include "mm/dumpmemory.h"
#include "mm/memory.h"

#include "toolbox/bitvector.h"

#include "vm/global.h"
#include "vm/jit/ir/bytecode.h"
#include "vm/jit/optimizing/escape.h"
#include "vm/resolve.h"

#include "vmcore/class.h"
#include "vmcore/descriptor.h"
#include "vmcore/references.h"

#include <assert.h>
#include <stdarg.h>

#define BC_ESCAPE_VERBOSE !defined(NDEBUG)

/*** dprintf *****************************************************************/

#if BC_ESCAPE_VERBOSE && 0
void dprintf(int depth, const char *fmt, ...) {
      va_list ap;

      while (depth-- > 0) {
            printf("    ");
      }
      printf("| ");

      va_start(ap, fmt);
      vprintf(fmt, ap);
      va_end(ap);
}
#endif

#define dprintf(x, ...) printf(__VA_ARGS__)

/*** op_stack_slot  **********************************************************/

typedef enum {
      OP_STACK_SLOT_TYPE_PARAM = 0,
      OP_STACK_SLOT_TYPE_UNKNOWN = 1
} op_stack_slot_type_t;

00069 typedef struct {
      unsigned type:1;
      unsigned index:31;
} op_stack_slot_t;

const op_stack_slot_t OP_STACK_SLOT_UNKNOWN = { 
      OP_STACK_SLOT_TYPE_UNKNOWN,
      0
};

static inline op_stack_slot_t op_stack_slot_create_param(s4 index) {
      op_stack_slot_t res;
      res.type = OP_STACK_SLOT_TYPE_PARAM;
      res.index = index;
      return res;
}

static inline bool op_stack_slot_is_unknown(const op_stack_slot_t slot) {
      return slot.type == OP_STACK_SLOT_TYPE_UNKNOWN;
}

static inline bool op_stack_slot_is_param(const op_stack_slot_t slot) {
      return slot.type == OP_STACK_SLOT_TYPE_PARAM;
}

/*** op_stack *****************************************************************/

/*

+---+---+---+---+  push 1
        ^

+---+---+-1-+---+  push 2
            ^

+---+---+-1-+-2-+  pop 2
                ^

+---+---+-1-+---+  pop 1
            ^        

+---+---+---+---+  
        ^
*/

00114 typedef struct {
      op_stack_slot_t *elements;
      op_stack_slot_t *start;
      op_stack_slot_t *end;
      op_stack_slot_t *ptr;
      op_stack_slot_t *bottom;
      unsigned max;
} 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) {
      op_stack_slot_t *it;

      stack->elements = DMNEW(op_stack_slot_t, max * 2);
      stack->max = max;
      stack->start = stack->elements + max;
      stack->end = stack->elements + max + max;

      for (it = stack->elements; it != stack->start; ++it) {
            *it = OP_STACK_SLOT_UNKNOWN;
      }

      stack->ptr = stack->start;
      stack->bottom = stack->start;
}

static void op_stack_reset(op_stack_t *stack) {
      op_stack_slot_t *it;

      /* Clear bottom half. */

      for (it = stack->bottom; it != stack->elements + stack->max; ++it) {
            *it = OP_STACK_SLOT_UNKNOWN;
      }

      /* Reset pointers. */

      stack->ptr = stack->start;
      stack->bottom = stack->start;
}

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);
      ret = *(stack->ptr);
      if (stack->ptr < stack->bottom) {
            stack->bottom = stack->ptr;
      }
      return ret;
}

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;
}

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);
}

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;
}

static inline void op_stack_push_unknown(op_stack_t *stack) {
      op_stack_push(stack, OP_STACK_SLOT_UNKNOWN);
}

static void op_stack_print(const op_stack_t *stack, FILE *f) {
      op_stack_slot_t *it;
      char sep;
      
      for (it = stack->bottom; it < stack->ptr; ++it) {
            if (it == stack->start) {
                  sep = '!';
            } else {
                  sep = '|';
            }
            if (op_stack_slot_is_unknown(*it)) {
                  fprintf(f, "%c----", sep);
            } else {
                  fprintf(f, "%cP%3d", sep, it->index);
            }
      }

      fprintf(f, "|");
}

static bool op_stack_is_empty(const op_stack_t *stack) {
      return !(stack->bottom < stack->ptr);
}

static s4 op_stack_element_count(const op_stack_t *stack) {
      return (stack->ptr - stack->bottom);
}

/*** bit_vector **************************************************************/

00221 typedef struct {
      bitvector bv;
      s4 size;
} bit_vector_t;

static void bit_vector_init(bit_vector_t *bv, s4 size) {
      bv->bv = bv_new(size);
      bv->size = size;
}

static s4 bit_vector_size(const bit_vector_t *bv) {
      return bv->size;
}

static void bit_vector_set(bit_vector_t *bv, s4 bit) {
      assert(0 <= bit && bit < bv->size);
      bv_set_bit(bv->bv, bit);
}

static bool bit_vector_get(const bit_vector_t *bv, s4 bit) {
      assert(0 <= bit && bit < bv->size);
      return bv_get_bit(bv->bv, bit);
}

/*** basicblock_work_list ***********************************************/

00247 typedef struct basicblock_work_item {
      s4 bytecode_index;
      struct basicblock_work_item *next;
} basicblock_work_item_t;

00252 typedef struct {
      basicblock_work_item_t *first;
      basicblock_work_item_t *last;
} basicblock_work_list_t;

void basicblock_work_list_init(basicblock_work_list_t *lst) {
      lst->first = NULL;
      lst->last = NULL;
}

#define FOR_EACH_BASICBLOCK_WORK_LIST(lst, it) \
      for ((it) = (lst)->first; (it); (it) = (it)->next)

void basicblock_work_list_insert(basicblock_work_list_t *lst, s4 bytecode_index) {
      basicblock_work_item_t *it, *item;

      /* If the destination is already present in the list, do nothing. */

      FOR_EACH_BASICBLOCK_WORK_LIST(lst, it) {
            if (it->bytecode_index == bytecode_index) {
                  return;
            }
      }

      item = DNEW(basicblock_work_item_t);
      item->bytecode_index = bytecode_index;
      item->next = NULL;

      if (lst->first == NULL) {
            lst->first = item;
            lst->last = item;
      } else {
            lst->last->next = item;
            lst->last = item;
      }
}

/*** value_category *****************************************************/

typedef enum {
      VALUE_CATEGORY_1,
      VALUE_CATEGORY_2
} value_category_t;

/*** jcode **************************************************************/

00298 typedef struct {
      u1 *start;
      u1 *end;
      u1 *pos;
      u1 *instruction_start;
      s4 offset;
} jcode_t;

static void jcode_init(jcode_t *jc, u1 *start, s4 length, s4 offset) {
      jc->start = start;
      jc->end = jc->start + length;
      jc->pos = jc->start;
      jc->offset = offset;
}

static void jcode_move_to_index(jcode_t *jc, s4 index) {
      jc->pos = jc->start + (index - jc->offset);
}

static bool jcode_end(const jcode_t *jc) {
      return (jc->pos >= jc->end);
}

static void jcode_record_instruction_start(jcode_t *jc) {
      jc->instruction_start = jc->pos;
}

static void jcode_rewind_instruction(jcode_t *jc) {
      jc->pos = jc->instruction_start;
}

static s4 jcode_get_instruction_length(const jcode_t *jc) {
      return (jc->pos - jc->instruction_start);
}

static void jcode_align_bytecode_index(jcode_t *jc, s4 align) {
      s4 idx, aidx;

      idx = jc->offset + (jc->pos - jc->start);
      aidx = MEMORY_ALIGN(idx, align);

      jc->pos += (aidx - idx);
}

static void jcode_forward_instruction_relative(jcode_t *jc, s4 n) {
      jc->pos = jc->instruction_start + n;
}

static s4 jcode_get_index(const jcode_t *jc) {
      return jc->offset + (jc->pos - jc->start);
}

#define jcode_assert_has_bytes(jc, n) \
      assert((jc->pos + n) <= jc->end)

static u1 jcode_get_u1(jcode_t *jc) {
      u1 ret;
      jcode_assert_has_bytes(jc, 1);
      ret = jc->pos[0];
      jc->pos += 1;
      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;
      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;
      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;
      return ret;
}

static s4 jcode_get_branch_target(jcode_t *jc) {
      s2 off = jcode_get_s2(jc);
      return jc->offset + (jc->instruction_start - jc->start) + off;
}

static s4 jcode_get_branch_target_wide(jcode_t *jc) {
      s4 off = jcode_get_s4(jc);
      return jc->offset + (jc->instruction_start - jc->start) + off;
}

static s4 jcode_get_fall_through_target(jcode_t *jc) {
      int length = bytecode[*jc->instruction_start].length;
      assert(length > 0);
      return jc->offset + (jc->instruction_start - jc->start) + length;
}

/*** bc_escape_analysis *************************************************/

00403 typedef struct {
      methodinfo *method;
      op_stack_t *stack;
      basicblock_work_list_t *basicblocks;

      op_stack_slot_t *local_to_adr_param;
      s4 local_to_adr_param_size;

      u1 *param_escape;
      s4 param_escape_size;

      bit_vector_t *adr_param_dirty;
      bit_vector_t *adr_param_returned;

      s4 non_escaping_adr_params;

#if BC_ESCAPE_VERBOSE
      bool verbose;
#endif
      int depth;
} bc_escape_analysis_t;

static void bc_escape_analysis_perform_intern(methodinfo *m, int depth);

static void bc_escape_analysis_init(bc_escape_analysis_t *be, methodinfo *m, bool verbose, int depth) {
      u2 p;
      int l;
      int a;
      u1 *ite;
      u1 t;
      int ret_adr;
      unsigned n;

      be->method = m;

      be->stack = DNEW(op_stack_t);
      op_stack_init(be->stack, m->maxstack);

      be->basicblocks = DNEW(basicblock_work_list_t);
      basicblock_work_list_init(be->basicblocks);

      be->local_to_adr_param_size = m->parseddesc->paramslots;
      be->local_to_adr_param = DMNEW(op_stack_slot_t, m->parseddesc->paramslots);

      /* Count number of address parameters a. */

      for (p = 0, l = 0, a = 0; p < m->parseddesc->paramcount; ++p) {
            t = m->parseddesc->paramtypes[p].type;
            if (t == TYPE_ADR) {
                  be->local_to_adr_param[l] = op_stack_slot_create_param(a);
                  a += 1;
                  l += 1;
            } else if (IS_2_WORD_TYPE(t)) {
                  be->local_to_adr_param[l] = OP_STACK_SLOT_UNKNOWN;
                  be->local_to_adr_param[l + 1] = OP_STACK_SLOT_UNKNOWN;
                  l += 2;
            } else {
                  be->local_to_adr_param[l] = OP_STACK_SLOT_UNKNOWN;
                  l += 1;
            }
      }

      assert(l == be->local_to_adr_param_size);

      /* Determine whether return type is address */

      ret_adr = m->parseddesc->returntype.type == TYPE_ADR ? 1 : 0;

      /* Allocate param_escape on heap. */

      be->param_escape_size = a;
      n = a + ret_adr;

      if (n == 0) {
            /* Use some non-NULL value. */
            be->param_escape = (u1 *)1;
      } else {
            be->param_escape = MNEW(u1, n);
      }

      for (ite = be->param_escape; ite != be->param_escape + n; ++ite) {
            *ite = (u1)ESCAPE_NONE;
      }

      be->param_escape += ret_adr;

      be->adr_param_dirty = DNEW(bit_vector_t);
      bit_vector_init(be->adr_param_dirty, a);

      be->adr_param_returned= DNEW(bit_vector_t);
      bit_vector_init(be->adr_param_returned, a);

      be->non_escaping_adr_params = be->param_escape_size;

#if BC_ESCAPE_VERBOSE
      be->verbose = verbose;
#endif

      be->depth = depth;
}

static void bc_escape_analysis_branch_target(bc_escape_analysis_t *be, s4 branch_target) {
      basicblock_work_list_insert(be->basicblocks, branch_target);
}

static void bc_escape_analysis_adjust_state(
      bc_escape_analysis_t *be, 
      op_stack_slot_t adr_param,
      escape_state_t escape_state
) {
      escape_state_t old;

      if (op_stack_slot_is_param(adr_param)) {
            if (0 <= adr_param.index && adr_param.index < be->param_escape_size) {
                  old = (escape_state_t)be->param_escape[adr_param.index];
                  if (old < escape_state) {

                        /* Adjust escape state. */
                        be->param_escape[adr_param.index] = (u1)escape_state;

                        /* If the parameter has just escaped, decrement number of non-escaping
                           parameters. */

                        if (
                              old < ESCAPE_GLOBAL_THROUGH_METHOD && 
                              escape_state >= ESCAPE_GLOBAL_THROUGH_METHOD
                        ) {
                              be->non_escaping_adr_params -= 1;
                        }
                  }
            }
      }
}

static void bc_escape_analysis_dirty(bc_escape_analysis_t *be, s4 local) {
      op_stack_slot_t adr_param;

      if (0 <= local && local < be->local_to_adr_param_size) {
            adr_param = be->local_to_adr_param[local];
            if (op_stack_slot_is_param(adr_param)) {
                  bit_vector_set(be->adr_param_dirty, adr_param.index);
            }
      }
}

static void bc_escape_analysis_dirty_2(bc_escape_analysis_t *be, s4 local) {
      bc_escape_analysis_dirty(be, local);
      bc_escape_analysis_dirty(be, local + 1);
}

static void bc_escape_analyisis_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. */
            if (be->method->parseddesc->returntype.type == TYPE_ADR) {
                  be->param_escape[-1] = (u1)ESCAPE_GLOBAL;
            }
      }
}

op_stack_slot_t bc_escape_analysis_address_local(bc_escape_analysis_t *be, s4 local) {
      if (0 <= local && local < be->local_to_adr_param_size) {
            return be->local_to_adr_param[local];
      } else {
            return OP_STACK_SLOT_UNKNOWN;
      }
}

value_category_t bc_escape_analysis_value_category(bc_escape_analysis_t *be, s4 index) {
      constant_FMIref *fmi;
      fmi = class_getconstant(be->method->clazz, index, CONSTANT_Fieldref);

      if (fmi == NULL) {
            /* TODO */
            assert(0);
      }

      switch (fmi->parseddesc.fd->type) {
            case TYPE_LNG:
            case TYPE_DBL:
                  return VALUE_CATEGORY_2;
            default:
                  return VALUE_CATEGORY_1;
      }
}

static void bc_escape_analysis_adjust_invoke_parameters(
      bc_escape_analysis_t *be,
      methodinfo *mi
) {
      int i;
      methoddesc *md = mi->parseddesc;
      u1 *paramescape = mi->paramescape;
      s4 stack_depth = md->paramslots;

      /* 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:
                        bc_escape_analysis_adjust_state(
                              be,
                              op_stack_get(be->stack, stack_depth),
                              (escape_state_t)*(paramescape++)
                        );
                        stack_depth -= 1;
                        break;
                  case TYPE_LNG:
                  case TYPE_DBL:
                        stack_depth -= 2;
                        break;
                  default:
                        stack_depth -= 1;
                        break;
            }
      }

      /* Pop all parameters. */

      for (i = 0; i < md->paramslots; ++i) {
            op_stack_pop(be->stack);
      }

}

static void bc_escape_analysis_escape_invoke_parameters(
      bc_escape_analysis_t *be,
      methoddesc *md
) {
      s4 i;
      for (i = 0; i < md->paramslots; ++i) {
            bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
      }
}

static void bc_escape_analysis_parse_invoke(bc_escape_analysis_t *be, jcode_t *jc) {
      constant_FMIref *fmi;
      methoddesc *md;
      u1 opc;
      u2 cp_index;
      s2 i;
      resolve_result_t result;
      methodinfo *mi;

      opc = jcode_get_u1(jc);
      cp_index = jcode_get_u2(jc);

      /* Get method reference */

      if (opc == BC_invokeinterface) {
            fmi = class_getconstant(be->method->clazz, cp_index, CONSTANT_InterfaceMethodref);
      } else {
            fmi = class_getconstant(be->method->clazz, cp_index, CONSTANT_Methodref);
      }

      if (fmi == NULL) {
            /* TODO */
            assert(0);
      }

      md = fmi->parseddesc.md;

      assert(md != NULL);

      /* Parse parameters if not done yet. */

      if (md->params == NULL) {
            if (! descriptor_params_from_paramtypes(md, opc == BC_invokestatic ? ACC_STATIC : 0)) {
                  /* TODO */
                  assert(0);
            }
      }

      /* Try to lazyly resolve method. */

      result = resolve_method_lazy(be->method, fmi, opc == BC_invokespecial);

      if (result == resolveSucceeded) {
            mi = fmi->p.method;

#if BC_ESCAPE_VERBOSE
            if (be->verbose) {
                  dprintf(
                        be->depth,
                        "Succefully resolved callee %s/%s. Recursing.\n",
                        mi->clazz->name->text,
                        mi->name->text
                  );
            }
#endif
      } else {
            mi = NULL;
#if BC_ESCAPE_VERBOSE
            if (be->verbose) {
                  dprintf(
                        be->depth,
                        "Failed to resolve callee %s/%s.\n", 
                        (IS_FMIREF_RESOLVED(fmi) ? "ERR" : fmi->p.classref->name->text),
                        fmi->name->text
                  );
            }
#endif
      }

      /* If we could resolve the method, either reuse available escape inormation
         or recurse into callee. 
         Otherwise we must assume, that all parameters escape. */

      if (mi != NULL) {

            if (mi->paramescape == NULL) {
                  bc_escape_analysis_perform_intern(mi, be->depth + 1);
            }

            if (mi->paramescape == NULL) {
                  /* No escape information. */
                  bc_escape_analysis_escape_invoke_parameters(be, md);
            } else {
                  /* Adjust escape state of parameters. */
                  bc_escape_analysis_adjust_invoke_parameters(be, mi);
            }

      } 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(
      bc_escape_analysis_t *be, 
      jcode_t *jc
) {
      s4 high, low, def;
      s4 i;

      jcode_get_u1(jc); /* opcode */

      jcode_align_bytecode_index(jc, 4);

      def = jcode_get_s4(jc);
      low = jcode_get_s4(jc);
      high = jcode_get_s4(jc);

      if (low <= high) {
            for (i = 0; i < (high - low + 1); ++i) {
                  bc_escape_analysis_branch_target(
                        be,
                        jcode_get_branch_target_wide(jc)
                  );
            }
      }

}

static void bc_escape_analysis_parse_lookupswitch(
      bc_escape_analysis_t *be, 
      jcode_t *jc
) {
      s4 npairs;
      s4 i;

      jcode_get_u1(jc); /* opcode */

      jcode_align_bytecode_index(jc, 4);

      /* default */

      bc_escape_analysis_branch_target(
            be,
            jcode_get_branch_target_wide(jc)
      );

      /* npairs */

      npairs = jcode_get_s4(jc);

      for (i = 0; i < npairs; ++i) {
            /* Match */
            jcode_get_s4(jc);

            /* Offset */
            bc_escape_analysis_branch_target(
                  be,
                  jcode_get_branch_target_wide(jc)
            );
      }

}

static void bc_escape_analysis_process_basicblock(bc_escape_analysis_t *be, jcode_t *jc) {
      u1 opc;
      op_stack_slot_t value1, value2, value3, value4;
      u1 dim;
      int length;
      bool bb_end = false;

#if BC_ESCAPE_VERBOSE
      if (be->verbose) {
            dprintf(be->depth, "Processing basicblock at offset %d.\n", jcode_get_index(jc));
      }
#endif

      op_stack_reset(be->stack);

      /* TODO end if all parameters escape */
      /* TODO move code into process_instruction or the like */

      while ((! jcode_end(jc)) && (! bb_end)) {

            jcode_record_instruction_start(jc);

            opc = jcode_get_u1(jc);

            length = bytecode[opc].length;

#if BC_ESCAPE_VERBOSE   
            if (be->verbose) {
                  dprintf(be->depth, "* %s, ", bytecode[opc].mnemonic);
                  op_stack_print(be->stack, stdout);
                  printf(" => ");
            }
#endif

            switch (opc) {
                  case BC_nop:
                        break;

                  case BC_aconst_null:
                  case BC_iconst_m1:
                  case BC_iconst_0:
                  case BC_iconst_1:
                  case BC_iconst_2:
                  case BC_iconst_3:
                  case BC_iconst_4:
                  case BC_iconst_5:
                  case BC_fconst_0:
                  case BC_fconst_1:
                  case BC_fconst_2:
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_dconst_0:
                  case BC_dconst_1:
                  case BC_lconst_0:
                  case BC_lconst_1:
                        op_stack_push_unknown(be->stack);
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_bipush:
                  case BC_sipush:
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_ldc1:
                  case BC_ldc2:
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_ldc2w:
                        op_stack_push_unknown(be->stack);
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_iload:
                  case BC_fload:
                  case BC_iload_0:
                  case BC_iload_1:
                  case BC_iload_2:
                  case BC_iload_3:
                  case BC_fload_0:
                  case BC_fload_1:
                  case BC_fload_2:
                  case BC_fload_3:
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_dload:
                  case BC_lload:
                  case BC_lload_0:
                  case BC_lload_1:
                  case BC_lload_2:
                  case BC_lload_3:
                  case BC_dload_0:
                  case BC_dload_1:
                  case BC_dload_2:
                  case BC_dload_3:
                        op_stack_push_unknown(be->stack);
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_aload:
                        op_stack_push(be->stack, bc_escape_analysis_address_local(be, jcode_get_u1(jc)));
                        break;

                  case BC_aload_0:
                        op_stack_push(be->stack, bc_escape_analysis_address_local(be, 0));
                        break;

                  case BC_aload_1:
                        op_stack_push(be->stack, bc_escape_analysis_address_local(be, 1));
                        break;

                  case BC_aload_2:
                        op_stack_push(be->stack, bc_escape_analysis_address_local(be, 2));
                        break;

                  case BC_aload_3:
                        op_stack_push(be->stack, bc_escape_analysis_address_local(be, 3));
                        break;

                  case BC_iaload:
                  case BC_faload:
                  case BC_baload:
                  case BC_caload:
                  case BC_saload:
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_laload:
                  case BC_daload:
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        op_stack_push_unknown(be->stack);
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_aaload:
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_istore:
                  case BC_fstore:
                        bc_escape_analysis_dirty(be, jcode_get_u1(jc));
                        op_stack_pop(be->stack);
                        break;

                  case BC_istore_0:
                  case BC_fstore_0:
                        bc_escape_analysis_dirty(be, 0);
                        op_stack_pop(be->stack);
                        break;

                  case BC_istore_1:
                  case BC_fstore_1:
                        bc_escape_analysis_dirty(be, 1);
                        op_stack_pop(be->stack);
                        break;

                  case BC_istore_2:
                  case BC_fstore_2:
                        bc_escape_analysis_dirty(be, 2);
                        op_stack_pop(be->stack);
                        break;

                  case BC_istore_3:
                  case BC_fstore_3:
                        bc_escape_analysis_dirty(be, 3);
                        op_stack_pop(be->stack);
                        break;

                  case BC_lstore:
                  case BC_dstore:
                        bc_escape_analysis_dirty_2(be, jcode_get_u1(jc));
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        break;

                  case BC_lstore_0:
                  case BC_dstore_0:
                        bc_escape_analysis_dirty_2(be, 0);
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        break;

                  case BC_lstore_1:
                  case BC_dstore_1:
                        bc_escape_analysis_dirty_2(be, 1);
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        break;

                  case BC_lstore_2:
                  case BC_dstore_2:
                        bc_escape_analysis_dirty_2(be, 2);
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        break;

                  case BC_lstore_3:
                  case BC_dstore_3:
                        bc_escape_analysis_dirty_2(be, 3);
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        break;

                  case BC_astore:
                        bc_escape_analysis_dirty(be, jcode_get_u1(jc));
                        bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
                        break;

                  case BC_astore_0:
                        bc_escape_analysis_dirty(be, 0);
                        bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
                        break;

                  case BC_astore_1:
                        bc_escape_analysis_dirty(be, 1);
                        bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
                        break;

                  case BC_astore_2:
                        bc_escape_analysis_dirty(be, 2);
                        bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
                        break;

                  case BC_astore_3:
                        bc_escape_analysis_dirty(be, 3);
                        bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
                        break;

                  case BC_iastore:
                  case BC_fastore:
                  case BC_bastore:
                  case BC_castore:
                  case BC_sastore:
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        break;

                  case BC_lastore:
                  case BC_dastore:
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        break;

                  case BC_aastore:
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
                        break;

                  case BC_pop:
                        op_stack_pop(be->stack);
                        break;

                  case BC_pop2:
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        break;

                  case BC_dup:
                        value1 = op_stack_get(be->stack, 1);
                        op_stack_push(be->stack, value1);
                        break;

                  case BC_dup_x1:
                        value1 = op_stack_pop(be->stack);
                        value2 = op_stack_pop(be->stack);
                        op_stack_push(be->stack, value1);
                        op_stack_push(be->stack, value2);
                        op_stack_push(be->stack, value1);
                        break;

                  case BC_dup_x2:
                        value1 = op_stack_pop(be->stack);
                        value2 = op_stack_pop(be->stack);
                        value3 = op_stack_pop(be->stack);
                        op_stack_push(be->stack, value1);
                        op_stack_push(be->stack, value3);
                        op_stack_push(be->stack, value2);
                        op_stack_push(be->stack, value1);
                        break;
                        
                  case BC_dup2:
                        value1 = op_stack_get(be->stack, 1);
                        value2 = op_stack_get(be->stack, 2);
                        op_stack_push(be->stack, value2);
                        op_stack_push(be->stack, value1);
                        break;

                  case BC_dup2_x1:
                        value1 = op_stack_pop(be->stack);
                        value2 = op_stack_pop(be->stack);
                        value3 = op_stack_pop(be->stack);
                        op_stack_push(be->stack, value2);
                        op_stack_push(be->stack, value1);
                        op_stack_push(be->stack, value3);
                        op_stack_push(be->stack, value2);
                        op_stack_push(be->stack, value1);
                        break;

                  case BC_dup2_x2:
                        value1 = op_stack_pop(be->stack);
                        value2 = op_stack_pop(be->stack);
                        value3 = op_stack_pop(be->stack);
                        value4 = op_stack_pop(be->stack);
                        op_stack_push(be->stack, value2);
                        op_stack_push(be->stack, value1);
                        op_stack_push(be->stack, value4);
                        op_stack_push(be->stack, value3);
                        op_stack_push(be->stack, value2);
                        op_stack_push(be->stack, value1);
                        break;

                  case BC_swap:
                        value1 = op_stack_get(be->stack, 1);
                        value2 = op_stack_get(be->stack, 2);
                        op_stack_set(be->stack, 1, value2);
                        op_stack_set(be->stack, 2, value1);
                        break;

                  case BC_iadd:
                  case BC_fadd:

                  case BC_isub:
                  case BC_fsub:

                  case BC_imul:
                  case BC_fmul:

                  case BC_idiv:
                  case BC_fdiv:

                  case BC_irem:
                  case BC_frem:

                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_ladd:
                  case BC_dadd:

                  case BC_lsub:
                  case BC_dsub:

                  case BC_ldiv:
                  case BC_ddiv:

                  case BC_lmul:
                  case BC_dmul:

                  case BC_lrem:
                  case BC_drem:

                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        op_stack_push_unknown(be->stack);
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_ineg:
                  case BC_lneg:
                  case BC_fneg:
                  case BC_dneg:

                        /* Nothing */
                        break;

                  case BC_ishl:
                  case BC_ishr:
                  case BC_iushr:
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_lshl:
                  case BC_lshr:
                  case BC_lushr:
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        /* Second operand is int. */
                        op_stack_pop(be->stack);
                        op_stack_push_unknown(be->stack);
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_iand:
                  case BC_ior:
                  case BC_ixor:
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_land:
                  case BC_lor:
                  case BC_lxor:
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        op_stack_push_unknown(be->stack);
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_iinc:
                        /* Not stack operation. */
                        bc_escape_analysis_dirty(be, jcode_get_u1(jc));
                        break;

                  case BC_i2l:
                  case BC_i2d:
                        op_stack_pop(be->stack);
                        op_stack_push_unknown(be->stack);
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_i2f:
                        op_stack_pop(be->stack);
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_l2i:
                  case BC_l2f:
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_l2d:
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        op_stack_push_unknown(be->stack);
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_f2i:
                        op_stack_pop(be->stack);
                        op_stack_push_unknown(be->stack);
                        break;
                        
                  case BC_f2l:
                  case BC_f2d:
                        op_stack_pop(be->stack);
                        op_stack_push_unknown(be->stack);
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_d2i:
                  case BC_d2f:
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_d2l:
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        op_stack_push_unknown(be->stack);
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_int2byte:
                  case BC_int2char:
                  case BC_int2short:
                        op_stack_pop(be->stack);
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_fcmpl:
                  case BC_fcmpg:
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_lcmp:
                  case BC_dcmpl:
                  case BC_dcmpg:
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_ifeq:
                  case BC_ifne:
                  case BC_iflt:
                  case BC_ifge:
                  case BC_ifgt:
                  case BC_ifle:
                        op_stack_pop(be->stack);
                        bc_escape_analysis_branch_target(be, jcode_get_branch_target(jc));
                        bc_escape_analysis_branch_target(be, jcode_get_fall_through_target(jc));
                        bb_end = true;
                        break;

                  case BC_if_icmpeq:
                  case BC_if_icmpne:
                  case BC_if_icmplt:
                  case BC_if_icmpge:
                  case BC_if_icmpgt:
                  case BC_if_icmple:
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        bc_escape_analysis_branch_target(be, jcode_get_branch_target(jc));
                        bc_escape_analysis_branch_target(be, jcode_get_fall_through_target(jc));
                        bb_end = true;
                        break;

                  case BC_if_acmpeq:
                  case BC_if_acmpne:
                        bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_METHOD);
                        bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_METHOD);
                        bc_escape_analysis_branch_target(be, jcode_get_branch_target(jc));
                        bc_escape_analysis_branch_target(be, jcode_get_fall_through_target(jc));
                        bb_end = true;
                        break;

                  case BC_goto:
                        bc_escape_analysis_branch_target(be, jcode_get_branch_target(jc));
                        bb_end = true;
                        break;

                  case BC_jsr:
                        op_stack_push_unknown(be->stack);
                        bc_escape_analysis_branch_target(be, jcode_get_branch_target(jc));
                        bb_end = true;
                        break;

                  case BC_ret:
                        break;

                  case BC_tableswitch:
                        op_stack_pop(be->stack);
                        jcode_rewind_instruction(jc);
                        bc_escape_analysis_parse_tableswitch(be, jc);
                        length = jcode_get_instruction_length(jc);
                        bb_end = 1;
                        break;

                  case BC_lookupswitch:
                        op_stack_pop(be->stack);
                        jcode_rewind_instruction(jc);
                        bc_escape_analysis_parse_lookupswitch(be, jc);
                        length = jcode_get_instruction_length(jc);
                        bb_end = 1;
                        break;

                  case BC_return:
                        bb_end = true;
                        break;

                  case BC_ireturn:
                  case BC_freturn:
                        op_stack_pop(be->stack);
                        bb_end = true;
                        break;

                  case BC_lreturn:
                  case BC_dreturn:
                        op_stack_pop(be->stack);
                        op_stack_pop(be->stack);
                        bb_end = true;
                        break;

                  case BC_areturn:
                        /* FIXME */
                        bc_escape_analyisis_returned(be, op_stack_pop(be->stack));
                        bb_end = true;
                        break;

                  case BC_getfield:
                        op_stack_pop(be->stack);
                        /* Fall through. */

                  case BC_getstatic:
                        if (
                              bc_escape_analysis_value_category(be, jcode_get_s2(jc)) == 
                              VALUE_CATEGORY_2
                        ) {
                              op_stack_push_unknown(be->stack);
                        }
                        op_stack_push_unknown(be->stack);
                        break;

                  
                  case BC_putfield:
                        if (
                              bc_escape_analysis_value_category(be, jcode_get_u2(jc)) == 
                              VALUE_CATEGORY_2
                        ) {
                              op_stack_pop(be->stack);

                              op_stack_pop(be->stack);
                              op_stack_pop(be->stack);
                        } else {
                              value2 = op_stack_pop(be->stack);
                              value1 = op_stack_pop(be->stack);
                              bc_escape_analysis_adjust_state(be, value2, ESCAPE_GLOBAL);
                        }
                        break;

                  case BC_putstatic:
                        if (
                              bc_escape_analysis_value_category(be, jcode_get_u2(jc)) == 
                              VALUE_CATEGORY_2
                        ) {
                              op_stack_pop(be->stack);
                              op_stack_pop(be->stack);
                        } else {
                              value1 = op_stack_pop(be->stack);
                              bc_escape_analysis_adjust_state(be, value1, ESCAPE_GLOBAL);
                        }
                        break;

                  case BC_invokevirtual:
                  case BC_invokespecial:
                  case BC_invokestatic:
                  case BC_invokeinterface:
                        jcode_rewind_instruction(jc);
                        bc_escape_analysis_parse_invoke(be, jc);
                        break;

                  case BC_new:
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_newarray:
                  case BC_anewarray:
                        op_stack_pop(be->stack);
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_arraylength:
                        bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_METHOD);
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_athrow:
                        bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
                        bb_end = true;
                        break;

                  case BC_checkcast:
                        value1 = op_stack_get(be->stack, 1);
                        bc_escape_analysis_adjust_state(be, value1, ESCAPE_METHOD);
                        break;

                  case BC_instanceof:
                        value1 = op_stack_pop(be->stack);
                        bc_escape_analysis_adjust_state(be, value1, ESCAPE_METHOD);
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_monitorenter:
                  case BC_monitorexit:
                        value1 = op_stack_pop(be->stack);
                        bc_escape_analysis_adjust_state(be, value1, ESCAPE_METHOD);
                        break;

                  case BC_wide:

                        /* All except iinc have a length of 4. */
                        length = 4;

                        switch (jcode_get_u1(jc)) {
                              case BC_iload:
                              case BC_fload:
                                    op_stack_push_unknown(be->stack);
                                    break;

                              case BC_lload:
                              case BC_dload:
                                    op_stack_push_unknown(be->stack);
                                    op_stack_push_unknown(be->stack);
                                    break;

                              case BC_aload:
                                    op_stack_push(
                                          be->stack, 
                                          bc_escape_analysis_address_local(
                                                be, 
                                                jcode_get_u1(jc)
                                          )
                                    );
                                    break;

                              case BC_istore:
                              case BC_fstore:
                                    bc_escape_analysis_dirty(be, jcode_get_u2(jc));
                                    op_stack_pop(be->stack);
                                    break;

                              case BC_lstore:
                              case BC_dstore:
                                    bc_escape_analysis_dirty_2(be, jcode_get_u2(jc));
                                    op_stack_pop(be->stack);
                                    op_stack_pop(be->stack);
                                    break;

                              case BC_astore:
                                    bc_escape_analysis_dirty(be, jcode_get_u2(jc));
                                    bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
                                    break;
                                    
                              case BC_ret:
                                    /* Do nothing. */
                                    break;

                              case BC_iinc:
                                    bc_escape_analysis_dirty(be, jcode_get_u2(jc));
                                    length = 6;
                                    /* Do nothing. */
                                    break;
                        }
                        break;

                  case BC_multianewarray:
                        jcode_get_u2(jc);
                        dim = jcode_get_u1(jc);
                        while (dim-- > 0) {
                              op_stack_pop(be->stack);
                        }
                        op_stack_push_unknown(be->stack);
                        break;

                  case BC_ifnull:
                  case BC_ifnonnull:
                        value1 = op_stack_pop(be->stack);
                        bc_escape_analysis_adjust_state(be, value1, ESCAPE_METHOD);
                        bc_escape_analysis_branch_target(be, jcode_get_branch_target(jc));
                        bc_escape_analysis_branch_target(be, jcode_get_fall_through_target(jc));
                        bb_end = true;
                        break;

                  case BC_goto_w:
                        bc_escape_analysis_branch_target(be, jcode_get_branch_target_wide(jc));
                        bb_end = true;
                        break;

                  case BC_jsr_w:
                        bc_escape_analysis_branch_target(be, jcode_get_branch_target_wide(jc));
                        bb_end = true;
                        break;

                  case BC_breakpoint:
                  case BC_impdep1:
                  case BC_impdep2:
                        break;

                  default:
                        break;
            }
            assert(length > 0);
            jcode_forward_instruction_relative(jc, length);

#if BC_ESCAPE_VERBOSE
            if (be->verbose) {
                  op_stack_print(be->stack, stdout);
                  printf("\n");
            }
#endif
      }

#if BC_ESCAPE_VERBOSE
      if (be->verbose) {
            dprintf(be->depth, "Elements left on stack: %d\n", op_stack_element_count(be->stack));
      }
#endif

      while (! op_stack_is_empty(be->stack)) {
#if BC_ESCAPE_VERBOSE
            if (be->verbose) {
                  dprintf(be->depth, "Stack element: ");
                  op_stack_print(be->stack, stdout);
                  printf(" => ");
            }
#endif
            bc_escape_analysis_adjust_state(be, op_stack_pop(be->stack), ESCAPE_GLOBAL);
#if BC_ESCAPE_VERBOSE
            if (be->verbose) {
                  op_stack_print(be->stack, stdout);
                  printf("\n");
            }
#endif
      }
}

static void bc_escape_analysis_adjust_return_value(bc_escape_analysis_t *be) {
      escape_state_t e, pe;
      int i;

      /* Only calculate, if return value is of type address. */

      if (be->method->parseddesc->returntype.type != TYPE_ADR) {
            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[-1] = (u1)e;
}

static void bc_escape_analysis_analyze(bc_escape_analysis_t *be) {
      raw_exception_entry *itee;
      basicblock_work_item_t *bb;
      jcode_t jc;

      /* Add root as basic block. */

      bc_escape_analysis_branch_target(be, 0);

      /* Add each exception handler as basic block. */

      for (
            itee = be->method->rawexceptiontable;
            itee != be->method->rawexceptiontable + be->method->rawexceptiontablelength;
            ++itee
      ) {
            bc_escape_analysis_branch_target(be, itee->handlerpc);
      }

      /* Init jcode parser. */

      jcode_init(
            &jc,
            be->method->jcode,
            be->method->jcodelength,
            0
      );

      /* Process basicblock by basicblock. */

      for (bb = be->basicblocks->first; bb; bb = bb->next) {
            jcode_move_to_index(&jc, bb->bytecode_index);
            bc_escape_analysis_process_basicblock(
                  be,
                  &jc
            );
      }

      /* Calculate escape of return value. */

      bc_escape_analysis_adjust_return_value(be);

      /* Export escape of parameters. */

      be->method->paramescape = be->param_escape;
}

static void bc_escape_analysis_perform_intern(methodinfo *m, int depth) {
      bc_escape_analysis_t *be;
      bool verbose = false;

#if BC_ESCAPE_VERBOSE
      if (verbose) {
            dprintf(
                  depth,
                  "=== BC escape analysis of %s/%s at depth %d ===\n",
                  m->clazz->name->text,
                  m->name->text,
                  depth
            );
      }
#endif

      if (m->paramescape != NULL) {
#if BC_ESCAPE_VERBOSE
            if (verbose) {    
                  dprintf(depth, "Escape info for method already available.\n");
            }
#endif
            return;
      }

      if ((m->flags & ACC_METHOD_EA) != 0) {
#if BC_ESCAPE_VERBOSE
            if (verbose) {    
                  dprintf(depth, "Detected recursion, aborting.\n");
            }
#endif
            return;
      }

      if (m->jcode == NULL) {
#if BC_ESCAPE_VERBOSE
            if (verbose) {
                  dprintf(depth, "No bytecode for callee.\n");
            }
#endif
            return;
      }

      /* TODO threshold */

      be = DNEW(bc_escape_analysis_t);
      bc_escape_analysis_init(be, m, verbose, depth);

      m->flags |= ACC_METHOD_EA;

      bc_escape_analysis_analyze(be);

#if BC_ESCAPE_VERBOSE
      if (be->verbose) {
            dprintf(
                  depth,
                  "%s/%s: Non-escaping params: %d\n", 
                  m->clazz->name->text,
                  m->name->text,
                  be->non_escaping_adr_params
            );
      }
#endif

      m->flags &= ~ACC_METHOD_EA;
}

void bc_escape_analysis_perform(methodinfo *m) {
      bc_escape_analysis_perform_intern(m, 0);
}



Generated by  Doxygen 1.6.0   Back to index