OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [gcc-4.5.1/] [gcc/] [java/] [expr.c] - Diff between revs 816 and 826

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 816 Rev 826
/* Process expressions for the GNU compiler for the Java(TM) language.
/* Process expressions for the GNU compiler for the Java(TM) language.
   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
   2005, 2006, 2007, 2008 Free Software Foundation, Inc.
   2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 
 
This file is part of GCC.
This file is part of GCC.
 
 
GCC is free software; you can redistribute it and/or modify
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
the Free Software Foundation; either version 3, or (at your option)
any later version.
any later version.
 
 
GCC is distributed in the hope that it will be useful,
GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
GNU General Public License for more details.
 
 
You should have received a copy of the GNU General Public License
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.
<http://www.gnu.org/licenses/>.
 
 
Java and all Java-based marks are trademarks or registered trademarks
Java and all Java-based marks are trademarks or registered trademarks
of Sun Microsystems, Inc. in the United States and other countries.
of Sun Microsystems, Inc. in the United States and other countries.
The Free Software Foundation is independent of Sun Microsystems, Inc.  */
The Free Software Foundation is independent of Sun Microsystems, Inc.  */
 
 
/* Hacked by Per Bothner <bothner@cygnus.com> February 1996. */
/* Hacked by Per Bothner <bothner@cygnus.com> February 1996. */
 
 
#include "config.h"
#include "config.h"
#include "system.h"
#include "system.h"
#include "coretypes.h"
#include "coretypes.h"
#include "tm.h"
#include "tm.h"
#include "tree.h"
#include "tree.h"
#include "real.h"
#include "real.h"
#include "rtl.h"
#include "rtl.h"
#include "flags.h"
#include "flags.h"
#include "expr.h"
#include "expr.h"
#include "java-tree.h"
#include "java-tree.h"
#include "javaop.h"
#include "javaop.h"
#include "java-opcodes.h"
#include "java-opcodes.h"
#include "jcf.h"
#include "jcf.h"
#include "java-except.h"
#include "java-except.h"
#include "parse.h"
#include "parse.h"
#include "toplev.h"
#include "toplev.h"
#include "except.h"
#include "except.h"
#include "tm_p.h"
#include "tm_p.h"
#include "ggc.h"
#include "ggc.h"
#include "tree-iterator.h"
#include "tree-iterator.h"
#include "gimple.h"
#include "gimple.h"
#include "target.h"
#include "target.h"
 
 
static void flush_quick_stack (void);
static void flush_quick_stack (void);
static void push_value (tree);
static void push_value (tree);
static tree pop_value (tree);
static tree pop_value (tree);
static void java_stack_swap (void);
static void java_stack_swap (void);
static void java_stack_dup (int, int);
static void java_stack_dup (int, int);
static void build_java_athrow (tree);
static void build_java_athrow (tree);
static void build_java_jsr (int, int);
static void build_java_jsr (int, int);
static void build_java_ret (tree);
static void build_java_ret (tree);
static void expand_java_multianewarray (tree, int);
static void expand_java_multianewarray (tree, int);
static void expand_java_arraystore (tree);
static void expand_java_arraystore (tree);
static void expand_java_arrayload (tree);
static void expand_java_arrayload (tree);
static void expand_java_array_length (void);
static void expand_java_array_length (void);
static tree build_java_monitor (tree, tree);
static tree build_java_monitor (tree, tree);
static void expand_java_pushc (int, tree);
static void expand_java_pushc (int, tree);
static void expand_java_return (tree);
static void expand_java_return (tree);
static void expand_load_internal (int, tree, int);
static void expand_load_internal (int, tree, int);
static void expand_java_NEW (tree);
static void expand_java_NEW (tree);
static void expand_java_INSTANCEOF (tree);
static void expand_java_INSTANCEOF (tree);
static void expand_java_CHECKCAST (tree);
static void expand_java_CHECKCAST (tree);
static void expand_iinc (unsigned int, int, int);
static void expand_iinc (unsigned int, int, int);
static void expand_java_binop (tree, enum tree_code);
static void expand_java_binop (tree, enum tree_code);
static void note_label (int, int);
static void note_label (int, int);
static void expand_compare (enum tree_code, tree, tree, int);
static void expand_compare (enum tree_code, tree, tree, int);
static void expand_test (enum tree_code, tree, int);
static void expand_test (enum tree_code, tree, int);
static void expand_cond (enum tree_code, tree, int);
static void expand_cond (enum tree_code, tree, int);
static void expand_java_goto (int);
static void expand_java_goto (int);
static tree expand_java_switch (tree, int);
static tree expand_java_switch (tree, int);
static void expand_java_add_case (tree, int, int);
static void expand_java_add_case (tree, int, int);
static tree pop_arguments (tree);
static tree pop_arguments (tree);
static void expand_invoke (int, int, int);
static void expand_invoke (int, int, int);
static void expand_java_field_op (int, int, int);
static void expand_java_field_op (int, int, int);
static void java_push_constant_from_pool (struct JCF *, int);
static void java_push_constant_from_pool (struct JCF *, int);
static void java_stack_pop (int);
static void java_stack_pop (int);
static tree build_java_throw_out_of_bounds_exception (tree);
static tree build_java_throw_out_of_bounds_exception (tree);
static tree build_java_check_indexed_type (tree, tree);
static tree build_java_check_indexed_type (tree, tree);
static unsigned char peek_opcode_at_pc (struct JCF *, int, int);
static unsigned char peek_opcode_at_pc (struct JCF *, int, int);
static void promote_arguments (void);
static void promote_arguments (void);
static void cache_cpool_data_ref (void);
static void cache_cpool_data_ref (void);
 
 
static GTY(()) tree operand_type[59];
static GTY(()) tree operand_type[59];
 
 
static GTY(()) tree methods_ident;
static GTY(()) tree methods_ident;
static GTY(()) tree ncode_ident;
static GTY(()) tree ncode_ident;
tree dtable_ident = NULL_TREE;
tree dtable_ident = NULL_TREE;
 
 
/* Set to nonzero value in order to emit class initialization code
/* Set to nonzero value in order to emit class initialization code
   before static field references.  */
   before static field references.  */
int always_initialize_class_p = 0;
int always_initialize_class_p = 0;
 
 
/* We store the stack state in two places:
/* We store the stack state in two places:
   Within a basic block, we use the quick_stack, which is a
   Within a basic block, we use the quick_stack, which is a
   pushdown list (TREE_LISTs) of expression nodes.
   pushdown list (TREE_LISTs) of expression nodes.
   This is the top part of the stack;  below that we use find_stack_slot.
   This is the top part of the stack;  below that we use find_stack_slot.
   At the end of a basic block, the quick_stack must be flushed
   At the end of a basic block, the quick_stack must be flushed
   to the stack slot array (as handled by find_stack_slot).
   to the stack slot array (as handled by find_stack_slot).
   Using quick_stack generates better code (especially when
   Using quick_stack generates better code (especially when
   compiled without optimization), because we do not have to
   compiled without optimization), because we do not have to
   explicitly store and load trees to temporary variables.
   explicitly store and load trees to temporary variables.
 
 
   If a variable is on the quick stack, it means the value of variable
   If a variable is on the quick stack, it means the value of variable
   when the quick stack was last flushed.  Conceptually, flush_quick_stack
   when the quick stack was last flushed.  Conceptually, flush_quick_stack
   saves all the quick_stack elements in parallel.  However, that is
   saves all the quick_stack elements in parallel.  However, that is
   complicated, so it actually saves them (i.e. copies each stack value
   complicated, so it actually saves them (i.e. copies each stack value
   to is home virtual register) from low indexes.  This allows a quick_stack
   to is home virtual register) from low indexes.  This allows a quick_stack
   element at index i (counting from the bottom of stack the) to references
   element at index i (counting from the bottom of stack the) to references
   slot virtuals for register that are >= i, but not those that are deeper.
   slot virtuals for register that are >= i, but not those that are deeper.
   This convention makes most operations easier.  For example iadd works
   This convention makes most operations easier.  For example iadd works
   even when the stack contains (reg[0], reg[1]):  It results in the
   even when the stack contains (reg[0], reg[1]):  It results in the
   stack containing (reg[0]+reg[1]), which is OK.  However, some stack
   stack containing (reg[0]+reg[1]), which is OK.  However, some stack
   operations are more complicated.  For example dup given a stack
   operations are more complicated.  For example dup given a stack
   containing (reg[0]) would yield (reg[0], reg[0]), which would violate
   containing (reg[0]) would yield (reg[0], reg[0]), which would violate
   the convention, since stack value 1 would refer to a register with
   the convention, since stack value 1 would refer to a register with
   lower index (reg[0]), which flush_quick_stack does not safely handle.
   lower index (reg[0]), which flush_quick_stack does not safely handle.
   So dup cannot just add an extra element to the quick_stack, but iadd can.
   So dup cannot just add an extra element to the quick_stack, but iadd can.
*/
*/
 
 
static GTY(()) tree quick_stack;
static GTY(()) tree quick_stack;
 
 
/* A free-list of unused permanent TREE_LIST nodes.  */
/* A free-list of unused permanent TREE_LIST nodes.  */
static GTY((deletable)) tree tree_list_free_list;
static GTY((deletable)) tree tree_list_free_list;
 
 
/* The physical memory page size used in this computer.  See
/* The physical memory page size used in this computer.  See
   build_field_ref().  */
   build_field_ref().  */
static GTY(()) tree page_size;
static GTY(()) tree page_size;
 
 
/* The stack pointer of the Java virtual machine.
/* The stack pointer of the Java virtual machine.
   This does include the size of the quick_stack. */
   This does include the size of the quick_stack. */
 
 
int stack_pointer;
int stack_pointer;
 
 
const unsigned char *linenumber_table;
const unsigned char *linenumber_table;
int linenumber_count;
int linenumber_count;
 
 
/* Largest pc so far in this method that has been passed to lookup_label. */
/* Largest pc so far in this method that has been passed to lookup_label. */
int highest_label_pc_this_method = -1;
int highest_label_pc_this_method = -1;
 
 
/* Base value for this method to add to pc to get generated label. */
/* Base value for this method to add to pc to get generated label. */
int start_label_pc_this_method = 0;
int start_label_pc_this_method = 0;
 
 
void
void
init_expr_processing (void)
init_expr_processing (void)
{
{
  operand_type[21] = operand_type[54] = int_type_node;
  operand_type[21] = operand_type[54] = int_type_node;
  operand_type[22] = operand_type[55] = long_type_node;
  operand_type[22] = operand_type[55] = long_type_node;
  operand_type[23] = operand_type[56] = float_type_node;
  operand_type[23] = operand_type[56] = float_type_node;
  operand_type[24] = operand_type[57] = double_type_node;
  operand_type[24] = operand_type[57] = double_type_node;
  operand_type[25] = operand_type[58] = ptr_type_node;
  operand_type[25] = operand_type[58] = ptr_type_node;
}
}
 
 
tree
tree
java_truthvalue_conversion (tree expr)
java_truthvalue_conversion (tree expr)
{
{
  /* It is simpler and generates better code to have only TRUTH_*_EXPR
  /* It is simpler and generates better code to have only TRUTH_*_EXPR
     or comparison expressions as truth values at this level.
     or comparison expressions as truth values at this level.
 
 
     This function should normally be identity for Java.  */
     This function should normally be identity for Java.  */
 
 
  switch (TREE_CODE (expr))
  switch (TREE_CODE (expr))
    {
    {
    case EQ_EXPR:   case NE_EXPR:   case UNEQ_EXPR: case LTGT_EXPR:
    case EQ_EXPR:   case NE_EXPR:   case UNEQ_EXPR: case LTGT_EXPR:
    case LE_EXPR:   case GE_EXPR:   case LT_EXPR:   case GT_EXPR:
    case LE_EXPR:   case GE_EXPR:   case LT_EXPR:   case GT_EXPR:
    case UNLE_EXPR: case UNGE_EXPR: case UNLT_EXPR: case UNGT_EXPR:
    case UNLE_EXPR: case UNGE_EXPR: case UNLT_EXPR: case UNGT_EXPR:
    case ORDERED_EXPR: case UNORDERED_EXPR:
    case ORDERED_EXPR: case UNORDERED_EXPR:
    case TRUTH_ANDIF_EXPR:
    case TRUTH_ANDIF_EXPR:
    case TRUTH_ORIF_EXPR:
    case TRUTH_ORIF_EXPR:
    case TRUTH_AND_EXPR:
    case TRUTH_AND_EXPR:
    case TRUTH_OR_EXPR:
    case TRUTH_OR_EXPR:
    case TRUTH_XOR_EXPR:
    case TRUTH_XOR_EXPR:
    case TRUTH_NOT_EXPR:
    case TRUTH_NOT_EXPR:
    case ERROR_MARK:
    case ERROR_MARK:
      return expr;
      return expr;
 
 
    case INTEGER_CST:
    case INTEGER_CST:
      return integer_zerop (expr) ? boolean_false_node : boolean_true_node;
      return integer_zerop (expr) ? boolean_false_node : boolean_true_node;
 
 
    case REAL_CST:
    case REAL_CST:
      return real_zerop (expr) ? boolean_false_node : boolean_true_node;
      return real_zerop (expr) ? boolean_false_node : boolean_true_node;
 
 
    /* are these legal? XXX JH */
    /* are these legal? XXX JH */
    case NEGATE_EXPR:
    case NEGATE_EXPR:
    case ABS_EXPR:
    case ABS_EXPR:
    case FLOAT_EXPR:
    case FLOAT_EXPR:
      /* These don't change whether an object is nonzero or zero.  */
      /* These don't change whether an object is nonzero or zero.  */
      return java_truthvalue_conversion (TREE_OPERAND (expr, 0));
      return java_truthvalue_conversion (TREE_OPERAND (expr, 0));
 
 
    case COND_EXPR:
    case COND_EXPR:
      /* Distribute the conversion into the arms of a COND_EXPR.  */
      /* Distribute the conversion into the arms of a COND_EXPR.  */
      return fold_build3 (COND_EXPR, boolean_type_node, TREE_OPERAND (expr, 0),
      return fold_build3 (COND_EXPR, boolean_type_node, TREE_OPERAND (expr, 0),
                          java_truthvalue_conversion (TREE_OPERAND (expr, 1)),
                          java_truthvalue_conversion (TREE_OPERAND (expr, 1)),
                          java_truthvalue_conversion (TREE_OPERAND (expr, 2)));
                          java_truthvalue_conversion (TREE_OPERAND (expr, 2)));
 
 
    case NOP_EXPR:
    case NOP_EXPR:
      /* If this is widening the argument, we can ignore it.  */
      /* If this is widening the argument, we can ignore it.  */
      if (TYPE_PRECISION (TREE_TYPE (expr))
      if (TYPE_PRECISION (TREE_TYPE (expr))
          >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0))))
          >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0))))
        return java_truthvalue_conversion (TREE_OPERAND (expr, 0));
        return java_truthvalue_conversion (TREE_OPERAND (expr, 0));
      /* fall through to default */
      /* fall through to default */
 
 
    default:
    default:
      return fold_build2 (NE_EXPR, boolean_type_node,
      return fold_build2 (NE_EXPR, boolean_type_node,
                          expr, boolean_false_node);
                          expr, boolean_false_node);
    }
    }
}
}
 
 
/* Save any stack slots that happen to be in the quick_stack into their
/* Save any stack slots that happen to be in the quick_stack into their
   home virtual register slots.
   home virtual register slots.
 
 
   The copy order is from low stack index to high, to support the invariant
   The copy order is from low stack index to high, to support the invariant
   that the expression for a slot may contain decls for stack slots with
   that the expression for a slot may contain decls for stack slots with
   higher (or the same) index, but not lower. */
   higher (or the same) index, but not lower. */
 
 
static void
static void
flush_quick_stack (void)
flush_quick_stack (void)
{
{
  int stack_index = stack_pointer;
  int stack_index = stack_pointer;
  tree prev, cur, next;
  tree prev, cur, next;
 
 
  /* First reverse the quick_stack, and count the number of slots it has. */
  /* First reverse the quick_stack, and count the number of slots it has. */
  for (cur = quick_stack, prev = NULL_TREE; cur != NULL_TREE; cur = next)
  for (cur = quick_stack, prev = NULL_TREE; cur != NULL_TREE; cur = next)
    {
    {
      next = TREE_CHAIN (cur);
      next = TREE_CHAIN (cur);
      TREE_CHAIN (cur) = prev;
      TREE_CHAIN (cur) = prev;
      prev = cur;
      prev = cur;
      stack_index -= 1 + TYPE_IS_WIDE (TREE_TYPE (TREE_VALUE (cur)));
      stack_index -= 1 + TYPE_IS_WIDE (TREE_TYPE (TREE_VALUE (cur)));
    }
    }
  quick_stack = prev;
  quick_stack = prev;
 
 
  while (quick_stack != NULL_TREE)
  while (quick_stack != NULL_TREE)
    {
    {
      tree decl;
      tree decl;
      tree node = quick_stack, type;
      tree node = quick_stack, type;
      quick_stack = TREE_CHAIN (node);
      quick_stack = TREE_CHAIN (node);
      TREE_CHAIN (node) = tree_list_free_list;
      TREE_CHAIN (node) = tree_list_free_list;
      tree_list_free_list = node;
      tree_list_free_list = node;
      node = TREE_VALUE (node);
      node = TREE_VALUE (node);
      type = TREE_TYPE (node);
      type = TREE_TYPE (node);
 
 
      decl = find_stack_slot (stack_index, type);
      decl = find_stack_slot (stack_index, type);
      if (decl != node)
      if (decl != node)
        java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (node), decl, node));
        java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (node), decl, node));
      stack_index += 1 + TYPE_IS_WIDE (type);
      stack_index += 1 + TYPE_IS_WIDE (type);
    }
    }
}
}
 
 
/* Push TYPE on the type stack.
/* Push TYPE on the type stack.
   Return true on success, 0 on overflow. */
   Return true on success, 0 on overflow. */
 
 
int
int
push_type_0 (tree type)
push_type_0 (tree type)
{
{
  int n_words;
  int n_words;
  type = promote_type (type);
  type = promote_type (type);
  n_words = 1 + TYPE_IS_WIDE (type);
  n_words = 1 + TYPE_IS_WIDE (type);
  if (stack_pointer + n_words > DECL_MAX_STACK (current_function_decl))
  if (stack_pointer + n_words > DECL_MAX_STACK (current_function_decl))
    return 0;
    return 0;
  /* Allocate decl for this variable now, so we get a temporary that
  /* Allocate decl for this variable now, so we get a temporary that
     survives the whole method. */
     survives the whole method. */
  find_stack_slot (stack_pointer, type);
  find_stack_slot (stack_pointer, type);
  stack_type_map[stack_pointer++] = type;
  stack_type_map[stack_pointer++] = type;
  n_words--;
  n_words--;
  while (--n_words >= 0)
  while (--n_words >= 0)
    stack_type_map[stack_pointer++] = TYPE_SECOND;
    stack_type_map[stack_pointer++] = TYPE_SECOND;
  return 1;
  return 1;
}
}
 
 
void
void
push_type (tree type)
push_type (tree type)
{
{
  int r = push_type_0 (type);
  int r = push_type_0 (type);
  gcc_assert (r);
  gcc_assert (r);
}
}
 
 
static void
static void
push_value (tree value)
push_value (tree value)
{
{
  tree type = TREE_TYPE (value);
  tree type = TREE_TYPE (value);
  if (TYPE_PRECISION (type) < 32 && INTEGRAL_TYPE_P (type))
  if (TYPE_PRECISION (type) < 32 && INTEGRAL_TYPE_P (type))
    {
    {
      type = promote_type (type);
      type = promote_type (type);
      value = convert (type, value);
      value = convert (type, value);
    }
    }
  push_type (type);
  push_type (type);
  if (tree_list_free_list == NULL_TREE)
  if (tree_list_free_list == NULL_TREE)
    quick_stack = tree_cons (NULL_TREE, value, quick_stack);
    quick_stack = tree_cons (NULL_TREE, value, quick_stack);
  else
  else
    {
    {
      tree node = tree_list_free_list;
      tree node = tree_list_free_list;
      tree_list_free_list = TREE_CHAIN (tree_list_free_list);
      tree_list_free_list = TREE_CHAIN (tree_list_free_list);
      TREE_VALUE (node) = value;
      TREE_VALUE (node) = value;
      TREE_CHAIN (node) = quick_stack;
      TREE_CHAIN (node) = quick_stack;
      quick_stack = node;
      quick_stack = node;
    }
    }
  /* If the value has a side effect, then we need to evaluate it
  /* If the value has a side effect, then we need to evaluate it
     whether or not the result is used.  If the value ends up on the
     whether or not the result is used.  If the value ends up on the
     quick stack and is then popped, this won't happen -- so we flush
     quick stack and is then popped, this won't happen -- so we flush
     the quick stack.  It is safest to simply always flush, though,
     the quick stack.  It is safest to simply always flush, though,
     since TREE_SIDE_EFFECTS doesn't capture COMPONENT_REF, and for
     since TREE_SIDE_EFFECTS doesn't capture COMPONENT_REF, and for
     the latter we may need to strip conversions.  */
     the latter we may need to strip conversions.  */
  flush_quick_stack ();
  flush_quick_stack ();
}
}
 
 
/* Pop a type from the type stack.
/* Pop a type from the type stack.
   TYPE is the expected type.   Return the actual type, which must be
   TYPE is the expected type.   Return the actual type, which must be
   convertible to TYPE.
   convertible to TYPE.
   On an error, *MESSAGEP is set to a freshly malloc'd error message. */
   On an error, *MESSAGEP is set to a freshly malloc'd error message. */
 
 
tree
tree
pop_type_0 (tree type, char **messagep)
pop_type_0 (tree type, char **messagep)
{
{
  int n_words;
  int n_words;
  tree t;
  tree t;
  *messagep = NULL;
  *messagep = NULL;
  if (TREE_CODE (type) == RECORD_TYPE)
  if (TREE_CODE (type) == RECORD_TYPE)
    type = promote_type (type);
    type = promote_type (type);
  n_words = 1 + TYPE_IS_WIDE (type);
  n_words = 1 + TYPE_IS_WIDE (type);
  if (stack_pointer < n_words)
  if (stack_pointer < n_words)
    {
    {
      *messagep = xstrdup ("stack underflow");
      *messagep = xstrdup ("stack underflow");
      return type;
      return type;
    }
    }
  while (--n_words > 0)
  while (--n_words > 0)
    {
    {
      if (stack_type_map[--stack_pointer] != void_type_node)
      if (stack_type_map[--stack_pointer] != void_type_node)
        {
        {
          *messagep = xstrdup ("Invalid multi-word value on type stack");
          *messagep = xstrdup ("Invalid multi-word value on type stack");
          return type;
          return type;
        }
        }
    }
    }
  t = stack_type_map[--stack_pointer];
  t = stack_type_map[--stack_pointer];
  if (type == NULL_TREE || t == type)
  if (type == NULL_TREE || t == type)
    return t;
    return t;
  if (TREE_CODE (t) == TREE_LIST)
  if (TREE_CODE (t) == TREE_LIST)
    {
    {
      do
      do
        {
        {
          tree tt = TREE_PURPOSE (t);
          tree tt = TREE_PURPOSE (t);
          if (! can_widen_reference_to (tt, type))
          if (! can_widen_reference_to (tt, type))
            {
            {
              t = tt;
              t = tt;
              goto fail;
              goto fail;
            }
            }
          t = TREE_CHAIN (t);
          t = TREE_CHAIN (t);
        }
        }
      while (t);
      while (t);
      return t;
      return t;
    }
    }
  if (INTEGRAL_TYPE_P (type) && INTEGRAL_TYPE_P (t)
  if (INTEGRAL_TYPE_P (type) && INTEGRAL_TYPE_P (t)
      && TYPE_PRECISION (type) <= 32 && TYPE_PRECISION (t) <= 32)
      && TYPE_PRECISION (type) <= 32 && TYPE_PRECISION (t) <= 32)
    return t;
    return t;
  if (TREE_CODE (type) == POINTER_TYPE && TREE_CODE (t) == POINTER_TYPE)
  if (TREE_CODE (type) == POINTER_TYPE && TREE_CODE (t) == POINTER_TYPE)
    {
    {
      /* If the expected type we've been passed is object or ptr
      /* If the expected type we've been passed is object or ptr
         (i.e. void*), the caller needs to know the real type.  */
         (i.e. void*), the caller needs to know the real type.  */
      if (type == ptr_type_node || type == object_ptr_type_node)
      if (type == ptr_type_node || type == object_ptr_type_node)
        return t;
        return t;
 
 
      /* Since the verifier has already run, we know that any
      /* Since the verifier has already run, we know that any
         types we see will be compatible.  In BC mode, this fact
         types we see will be compatible.  In BC mode, this fact
         may be checked at runtime, but if that is so then we can
         may be checked at runtime, but if that is so then we can
         assume its truth here as well.  So, we always succeed
         assume its truth here as well.  So, we always succeed
         here, with the expected type.  */
         here, with the expected type.  */
      return type;
      return type;
    }
    }
 
 
  if (! flag_verify_invocations && flag_indirect_dispatch
  if (! flag_verify_invocations && flag_indirect_dispatch
      && t == object_ptr_type_node)
      && t == object_ptr_type_node)
    {
    {
      if (type != ptr_type_node)
      if (type != ptr_type_node)
        warning (0, "need to insert runtime check for %s",
        warning (0, "need to insert runtime check for %s",
                 xstrdup (lang_printable_name (type, 0)));
                 xstrdup (lang_printable_name (type, 0)));
      return type;
      return type;
    }
    }
 
 
  /* lang_printable_name uses a static buffer, so we must save the result
  /* lang_printable_name uses a static buffer, so we must save the result
     from calling it the first time.  */
     from calling it the first time.  */
 fail:
 fail:
  {
  {
    char *temp = xstrdup (lang_printable_name (type, 0));
    char *temp = xstrdup (lang_printable_name (type, 0));
    /* If the stack contains a multi-word type, keep popping the stack until
    /* If the stack contains a multi-word type, keep popping the stack until
       the real type is found.  */
       the real type is found.  */
    while (t == void_type_node)
    while (t == void_type_node)
      t = stack_type_map[--stack_pointer];
      t = stack_type_map[--stack_pointer];
    *messagep = concat ("expected type '", temp,
    *messagep = concat ("expected type '", temp,
                        "' but stack contains '", lang_printable_name (t, 0),
                        "' but stack contains '", lang_printable_name (t, 0),
                        "'", NULL);
                        "'", NULL);
    free (temp);
    free (temp);
  }
  }
  return type;
  return type;
}
}
 
 
/* Pop a type from the type stack.
/* Pop a type from the type stack.
   TYPE is the expected type.  Return the actual type, which must be
   TYPE is the expected type.  Return the actual type, which must be
   convertible to TYPE, otherwise call error. */
   convertible to TYPE, otherwise call error. */
 
 
tree
tree
pop_type (tree type)
pop_type (tree type)
{
{
  char *message = NULL;
  char *message = NULL;
  type = pop_type_0 (type, &message);
  type = pop_type_0 (type, &message);
  if (message != NULL)
  if (message != NULL)
    {
    {
      error ("%s", message);
      error ("%s", message);
      free (message);
      free (message);
    }
    }
  return type;
  return type;
}
}
 
 


/* Return true if two type assertions are equal.  */
/* Return true if two type assertions are equal.  */
 
 
static int
static int
type_assertion_eq (const void * k1_p, const void * k2_p)
type_assertion_eq (const void * k1_p, const void * k2_p)
{
{
  const type_assertion k1 = *(const type_assertion *)k1_p;
  const type_assertion k1 = *(const type_assertion *)k1_p;
  const type_assertion k2 = *(const type_assertion *)k2_p;
  const type_assertion k2 = *(const type_assertion *)k2_p;
  return (k1.assertion_code == k2.assertion_code
  return (k1.assertion_code == k2.assertion_code
          && k1.op1 == k2.op1
          && k1.op1 == k2.op1
          && k1.op2 == k2.op2);
          && k1.op2 == k2.op2);
}
}
 
 
/* Hash a type assertion.  */
/* Hash a type assertion.  */
 
 
static hashval_t
static hashval_t
type_assertion_hash (const void *p)
type_assertion_hash (const void *p)
{
{
  const type_assertion *k_p = (const type_assertion *) p;
  const type_assertion *k_p = (const type_assertion *) p;
  hashval_t hash = iterative_hash (&k_p->assertion_code, sizeof
  hashval_t hash = iterative_hash (&k_p->assertion_code, sizeof
                                   k_p->assertion_code, 0);
                                   k_p->assertion_code, 0);
 
 
  switch (k_p->assertion_code)
  switch (k_p->assertion_code)
    {
    {
    case JV_ASSERT_TYPES_COMPATIBLE:
    case JV_ASSERT_TYPES_COMPATIBLE:
      hash = iterative_hash (&TYPE_UID (k_p->op2), sizeof TYPE_UID (k_p->op2),
      hash = iterative_hash (&TYPE_UID (k_p->op2), sizeof TYPE_UID (k_p->op2),
                             hash);
                             hash);
      /* Fall through.  */
      /* Fall through.  */
 
 
    case JV_ASSERT_IS_INSTANTIABLE:
    case JV_ASSERT_IS_INSTANTIABLE:
      hash = iterative_hash (&TYPE_UID (k_p->op1), sizeof TYPE_UID (k_p->op1),
      hash = iterative_hash (&TYPE_UID (k_p->op1), sizeof TYPE_UID (k_p->op1),
                             hash);
                             hash);
      /* Fall through.  */
      /* Fall through.  */
 
 
    case JV_ASSERT_END_OF_TABLE:
    case JV_ASSERT_END_OF_TABLE:
      break;
      break;
 
 
    default:
    default:
      gcc_unreachable ();
      gcc_unreachable ();
    }
    }
 
 
  return hash;
  return hash;
}
}
 
 
/* Add an entry to the type assertion table for the given class.
/* Add an entry to the type assertion table for the given class.
   KLASS is the class for which this assertion will be evaluated by the
   KLASS is the class for which this assertion will be evaluated by the
   runtime during loading/initialization.
   runtime during loading/initialization.
   ASSERTION_CODE is the 'opcode' or type of this assertion: see java-tree.h.
   ASSERTION_CODE is the 'opcode' or type of this assertion: see java-tree.h.
   OP1 and OP2 are the operands. The tree type of these arguments may be
   OP1 and OP2 are the operands. The tree type of these arguments may be
   specific to each assertion_code. */
   specific to each assertion_code. */
 
 
void
void
add_type_assertion (tree klass, int assertion_code, tree op1, tree op2)
add_type_assertion (tree klass, int assertion_code, tree op1, tree op2)
{
{
  htab_t assertions_htab;
  htab_t assertions_htab;
  type_assertion as;
  type_assertion as;
  void **as_pp;
  void **as_pp;
 
 
  assertions_htab = TYPE_ASSERTIONS (klass);
  assertions_htab = TYPE_ASSERTIONS (klass);
  if (assertions_htab == NULL)
  if (assertions_htab == NULL)
    {
    {
      assertions_htab = htab_create_ggc (7, type_assertion_hash,
      assertions_htab = htab_create_ggc (7, type_assertion_hash,
                                         type_assertion_eq, NULL);
                                         type_assertion_eq, NULL);
      TYPE_ASSERTIONS (current_class) = assertions_htab;
      TYPE_ASSERTIONS (current_class) = assertions_htab;
    }
    }
 
 
  as.assertion_code = assertion_code;
  as.assertion_code = assertion_code;
  as.op1 = op1;
  as.op1 = op1;
  as.op2 = op2;
  as.op2 = op2;
 
 
  as_pp = htab_find_slot (assertions_htab, &as, INSERT);
  as_pp = htab_find_slot (assertions_htab, &as, INSERT);
 
 
  /* Don't add the same assertion twice.  */
  /* Don't add the same assertion twice.  */
  if (*as_pp)
  if (*as_pp)
    return;
    return;
 
 
  *as_pp = ggc_alloc (sizeof (type_assertion));
  *as_pp = ggc_alloc (sizeof (type_assertion));
  **(type_assertion **)as_pp = as;
  **(type_assertion **)as_pp = as;
}
}
 
 


/* Return 1 if SOURCE_TYPE can be safely widened to TARGET_TYPE.
/* Return 1 if SOURCE_TYPE can be safely widened to TARGET_TYPE.
   Handles array types and interfaces.  */
   Handles array types and interfaces.  */
 
 
int
int
can_widen_reference_to (tree source_type, tree target_type)
can_widen_reference_to (tree source_type, tree target_type)
{
{
  if (source_type == ptr_type_node || target_type == object_ptr_type_node)
  if (source_type == ptr_type_node || target_type == object_ptr_type_node)
    return 1;
    return 1;
 
 
  /* Get rid of pointers  */
  /* Get rid of pointers  */
  if (TREE_CODE (source_type) == POINTER_TYPE)
  if (TREE_CODE (source_type) == POINTER_TYPE)
    source_type = TREE_TYPE (source_type);
    source_type = TREE_TYPE (source_type);
  if (TREE_CODE (target_type) == POINTER_TYPE)
  if (TREE_CODE (target_type) == POINTER_TYPE)
    target_type = TREE_TYPE (target_type);
    target_type = TREE_TYPE (target_type);
 
 
  if (source_type == target_type)
  if (source_type == target_type)
    return 1;
    return 1;
 
 
  /* FIXME: This is very pessimistic, in that it checks everything,
  /* FIXME: This is very pessimistic, in that it checks everything,
     even if we already know that the types are compatible.  If we're
     even if we already know that the types are compatible.  If we're
     to support full Java class loader semantics, we need this.
     to support full Java class loader semantics, we need this.
     However, we could do something more optimal.  */
     However, we could do something more optimal.  */
  if (! flag_verify_invocations)
  if (! flag_verify_invocations)
    {
    {
      add_type_assertion (current_class, JV_ASSERT_TYPES_COMPATIBLE,
      add_type_assertion (current_class, JV_ASSERT_TYPES_COMPATIBLE,
                          source_type, target_type);
                          source_type, target_type);
 
 
      if (!quiet_flag)
      if (!quiet_flag)
       warning (0, "assert: %s is assign compatible with %s",
       warning (0, "assert: %s is assign compatible with %s",
                xstrdup (lang_printable_name (target_type, 0)),
                xstrdup (lang_printable_name (target_type, 0)),
                xstrdup (lang_printable_name (source_type, 0)));
                xstrdup (lang_printable_name (source_type, 0)));
      /* Punt everything to runtime.  */
      /* Punt everything to runtime.  */
      return 1;
      return 1;
    }
    }
 
 
  if (TYPE_DUMMY (source_type) || TYPE_DUMMY (target_type))
  if (TYPE_DUMMY (source_type) || TYPE_DUMMY (target_type))
    {
    {
      return 1;
      return 1;
    }
    }
  else
  else
    {
    {
      if (TYPE_ARRAY_P (source_type) || TYPE_ARRAY_P (target_type))
      if (TYPE_ARRAY_P (source_type) || TYPE_ARRAY_P (target_type))
        {
        {
          HOST_WIDE_INT source_length, target_length;
          HOST_WIDE_INT source_length, target_length;
          if (TYPE_ARRAY_P (source_type) != TYPE_ARRAY_P (target_type))
          if (TYPE_ARRAY_P (source_type) != TYPE_ARRAY_P (target_type))
            {
            {
              /* An array implements Cloneable and Serializable.  */
              /* An array implements Cloneable and Serializable.  */
              tree name = DECL_NAME (TYPE_NAME (target_type));
              tree name = DECL_NAME (TYPE_NAME (target_type));
              return (name == java_lang_cloneable_identifier_node
              return (name == java_lang_cloneable_identifier_node
                      || name == java_io_serializable_identifier_node);
                      || name == java_io_serializable_identifier_node);
            }
            }
          target_length = java_array_type_length (target_type);
          target_length = java_array_type_length (target_type);
          if (target_length >= 0)
          if (target_length >= 0)
            {
            {
              source_length = java_array_type_length (source_type);
              source_length = java_array_type_length (source_type);
              if (source_length != target_length)
              if (source_length != target_length)
                return 0;
                return 0;
            }
            }
          source_type = TYPE_ARRAY_ELEMENT (source_type);
          source_type = TYPE_ARRAY_ELEMENT (source_type);
          target_type = TYPE_ARRAY_ELEMENT (target_type);
          target_type = TYPE_ARRAY_ELEMENT (target_type);
          if (source_type == target_type)
          if (source_type == target_type)
            return 1;
            return 1;
          if (TREE_CODE (source_type) != POINTER_TYPE
          if (TREE_CODE (source_type) != POINTER_TYPE
              || TREE_CODE (target_type) != POINTER_TYPE)
              || TREE_CODE (target_type) != POINTER_TYPE)
            return 0;
            return 0;
          return can_widen_reference_to (source_type, target_type);
          return can_widen_reference_to (source_type, target_type);
        }
        }
      else
      else
        {
        {
          int source_depth = class_depth (source_type);
          int source_depth = class_depth (source_type);
          int target_depth = class_depth (target_type);
          int target_depth = class_depth (target_type);
 
 
          if (TYPE_DUMMY (source_type) || TYPE_DUMMY (target_type))
          if (TYPE_DUMMY (source_type) || TYPE_DUMMY (target_type))
            {
            {
              if (! quiet_flag)
              if (! quiet_flag)
                warning (0, "assert: %s is assign compatible with %s",
                warning (0, "assert: %s is assign compatible with %s",
                         xstrdup (lang_printable_name (target_type, 0)),
                         xstrdup (lang_printable_name (target_type, 0)),
                         xstrdup (lang_printable_name (source_type, 0)));
                         xstrdup (lang_printable_name (source_type, 0)));
              return 1;
              return 1;
            }
            }
 
 
          /* class_depth can return a negative depth if an error occurred */
          /* class_depth can return a negative depth if an error occurred */
          if (source_depth < 0 || target_depth < 0)
          if (source_depth < 0 || target_depth < 0)
            return 0;
            return 0;
 
 
          if (CLASS_INTERFACE (TYPE_NAME (target_type)))
          if (CLASS_INTERFACE (TYPE_NAME (target_type)))
            {
            {
              /* target_type is OK if source_type or source_type ancestors
              /* target_type is OK if source_type or source_type ancestors
                 implement target_type. We handle multiple sub-interfaces  */
                 implement target_type. We handle multiple sub-interfaces  */
              tree binfo, base_binfo;
              tree binfo, base_binfo;
              int i;
              int i;
 
 
              for (binfo = TYPE_BINFO (source_type), i = 0;
              for (binfo = TYPE_BINFO (source_type), i = 0;
                   BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
                   BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
                if (can_widen_reference_to
                if (can_widen_reference_to
                    (BINFO_TYPE (base_binfo), target_type))
                    (BINFO_TYPE (base_binfo), target_type))
                  return 1;
                  return 1;
 
 
              if (!i)
              if (!i)
                return 0;
                return 0;
            }
            }
 
 
          for ( ; source_depth > target_depth;  source_depth--)
          for ( ; source_depth > target_depth;  source_depth--)
            {
            {
              source_type
              source_type
                = BINFO_TYPE (BINFO_BASE_BINFO (TYPE_BINFO (source_type), 0));
                = BINFO_TYPE (BINFO_BASE_BINFO (TYPE_BINFO (source_type), 0));
            }
            }
          return source_type == target_type;
          return source_type == target_type;
        }
        }
    }
    }
}
}
 
 
static tree
static tree
pop_value (tree type)
pop_value (tree type)
{
{
  type = pop_type (type);
  type = pop_type (type);
  if (quick_stack)
  if (quick_stack)
    {
    {
      tree node = quick_stack;
      tree node = quick_stack;
      quick_stack = TREE_CHAIN (quick_stack);
      quick_stack = TREE_CHAIN (quick_stack);
      TREE_CHAIN (node) = tree_list_free_list;
      TREE_CHAIN (node) = tree_list_free_list;
      tree_list_free_list = node;
      tree_list_free_list = node;
      node = TREE_VALUE (node);
      node = TREE_VALUE (node);
      return node;
      return node;
    }
    }
  else
  else
    return find_stack_slot (stack_pointer, promote_type (type));
    return find_stack_slot (stack_pointer, promote_type (type));
}
}
 
 
 
 
/* Pop and discard the top COUNT stack slots. */
/* Pop and discard the top COUNT stack slots. */
 
 
static void
static void
java_stack_pop (int count)
java_stack_pop (int count)
{
{
  while (count > 0)
  while (count > 0)
    {
    {
      tree type;
      tree type;
 
 
      gcc_assert (stack_pointer != 0);
      gcc_assert (stack_pointer != 0);
 
 
      type = stack_type_map[stack_pointer - 1];
      type = stack_type_map[stack_pointer - 1];
      if (type == TYPE_SECOND)
      if (type == TYPE_SECOND)
        {
        {
          count--;
          count--;
          gcc_assert (stack_pointer != 1 && count > 0);
          gcc_assert (stack_pointer != 1 && count > 0);
 
 
          type = stack_type_map[stack_pointer - 2];
          type = stack_type_map[stack_pointer - 2];
        }
        }
      pop_value (type);
      pop_value (type);
      count--;
      count--;
    }
    }
}
}
 
 
/* Implement the 'swap' operator (to swap two top stack slots). */
/* Implement the 'swap' operator (to swap two top stack slots). */
 
 
static void
static void
java_stack_swap (void)
java_stack_swap (void)
{
{
  tree type1, type2;
  tree type1, type2;
  tree temp;
  tree temp;
  tree decl1, decl2;
  tree decl1, decl2;
 
 
  if (stack_pointer < 2
  if (stack_pointer < 2
      || (type1 = stack_type_map[stack_pointer - 1]) == TYPE_SECOND
      || (type1 = stack_type_map[stack_pointer - 1]) == TYPE_SECOND
      || (type2 = stack_type_map[stack_pointer - 2]) == TYPE_SECOND
      || (type2 = stack_type_map[stack_pointer - 2]) == TYPE_SECOND
      || TYPE_IS_WIDE (type1) || TYPE_IS_WIDE (type2))
      || TYPE_IS_WIDE (type1) || TYPE_IS_WIDE (type2))
    /* Bad stack swap.  */
    /* Bad stack swap.  */
    abort ();
    abort ();
  /* Bad stack swap.  */
  /* Bad stack swap.  */
 
 
  flush_quick_stack ();
  flush_quick_stack ();
  decl1 = find_stack_slot (stack_pointer - 1, type1);
  decl1 = find_stack_slot (stack_pointer - 1, type1);
  decl2 = find_stack_slot (stack_pointer - 2, type2);
  decl2 = find_stack_slot (stack_pointer - 2, type2);
  temp = build_decl (input_location, VAR_DECL, NULL_TREE, type1);
  temp = build_decl (input_location, VAR_DECL, NULL_TREE, type1);
  java_add_local_var (temp);
  java_add_local_var (temp);
  java_add_stmt (build2 (MODIFY_EXPR, type1, temp, decl1));
  java_add_stmt (build2 (MODIFY_EXPR, type1, temp, decl1));
  java_add_stmt (build2 (MODIFY_EXPR, type2,
  java_add_stmt (build2 (MODIFY_EXPR, type2,
                         find_stack_slot (stack_pointer - 1, type2),
                         find_stack_slot (stack_pointer - 1, type2),
                         decl2));
                         decl2));
  java_add_stmt (build2 (MODIFY_EXPR, type1,
  java_add_stmt (build2 (MODIFY_EXPR, type1,
                         find_stack_slot (stack_pointer - 2, type1),
                         find_stack_slot (stack_pointer - 2, type1),
                         temp));
                         temp));
  stack_type_map[stack_pointer - 1] = type2;
  stack_type_map[stack_pointer - 1] = type2;
  stack_type_map[stack_pointer - 2] = type1;
  stack_type_map[stack_pointer - 2] = type1;
}
}
 
 
static void
static void
java_stack_dup (int size, int offset)
java_stack_dup (int size, int offset)
{
{
  int low_index = stack_pointer - size - offset;
  int low_index = stack_pointer - size - offset;
  int dst_index;
  int dst_index;
  if (low_index < 0)
  if (low_index < 0)
    error ("stack underflow - dup* operation");
    error ("stack underflow - dup* operation");
 
 
  flush_quick_stack ();
  flush_quick_stack ();
 
 
  stack_pointer += size;
  stack_pointer += size;
  dst_index = stack_pointer;
  dst_index = stack_pointer;
 
 
  for (dst_index = stack_pointer;  --dst_index >= low_index; )
  for (dst_index = stack_pointer;  --dst_index >= low_index; )
    {
    {
      tree type;
      tree type;
      int src_index = dst_index - size;
      int src_index = dst_index - size;
      if (src_index < low_index)
      if (src_index < low_index)
        src_index = dst_index + size + offset;
        src_index = dst_index + size + offset;
      type = stack_type_map [src_index];
      type = stack_type_map [src_index];
      if (type == TYPE_SECOND)
      if (type == TYPE_SECOND)
        {
        {
          /* Dup operation splits 64-bit number.  */
          /* Dup operation splits 64-bit number.  */
          gcc_assert (src_index > low_index);
          gcc_assert (src_index > low_index);
 
 
          stack_type_map[dst_index] = type;
          stack_type_map[dst_index] = type;
          src_index--;  dst_index--;
          src_index--;  dst_index--;
          type = stack_type_map[src_index];
          type = stack_type_map[src_index];
          gcc_assert (TYPE_IS_WIDE (type));
          gcc_assert (TYPE_IS_WIDE (type));
        }
        }
      else
      else
        gcc_assert (! TYPE_IS_WIDE (type));
        gcc_assert (! TYPE_IS_WIDE (type));
 
 
      if (src_index != dst_index)
      if (src_index != dst_index)
        {
        {
          tree src_decl = find_stack_slot (src_index, type);
          tree src_decl = find_stack_slot (src_index, type);
          tree dst_decl = find_stack_slot (dst_index, type);
          tree dst_decl = find_stack_slot (dst_index, type);
 
 
          java_add_stmt
          java_add_stmt
            (build2 (MODIFY_EXPR, TREE_TYPE (dst_decl), dst_decl, src_decl));
            (build2 (MODIFY_EXPR, TREE_TYPE (dst_decl), dst_decl, src_decl));
          stack_type_map[dst_index] = type;
          stack_type_map[dst_index] = type;
        }
        }
    }
    }
}
}
 
 
/* Calls _Jv_Throw or _Jv_Sjlj_Throw.  Discard the contents of the
/* Calls _Jv_Throw or _Jv_Sjlj_Throw.  Discard the contents of the
   value stack. */
   value stack. */
 
 
static void
static void
build_java_athrow (tree node)
build_java_athrow (tree node)
{
{
  tree call;
  tree call;
 
 
  call = build_call_nary (void_type_node,
  call = build_call_nary (void_type_node,
                          build_address_of (throw_node),
                          build_address_of (throw_node),
                          1, node);
                          1, node);
  TREE_SIDE_EFFECTS (call) = 1;
  TREE_SIDE_EFFECTS (call) = 1;
  java_add_stmt (call);
  java_add_stmt (call);
  java_stack_pop (stack_pointer);
  java_stack_pop (stack_pointer);
}
}
 
 
/* Implementation for jsr/ret */
/* Implementation for jsr/ret */
 
 
static void
static void
build_java_jsr (int target_pc, int return_pc)
build_java_jsr (int target_pc, int return_pc)
{
{
  tree where =  lookup_label (target_pc);
  tree where =  lookup_label (target_pc);
  tree ret = lookup_label (return_pc);
  tree ret = lookup_label (return_pc);
  tree ret_label = fold_build1 (ADDR_EXPR, return_address_type_node, ret);
  tree ret_label = fold_build1 (ADDR_EXPR, return_address_type_node, ret);
  push_value (ret_label);
  push_value (ret_label);
  flush_quick_stack ();
  flush_quick_stack ();
  java_add_stmt (build1 (GOTO_EXPR, void_type_node, where));
  java_add_stmt (build1 (GOTO_EXPR, void_type_node, where));
 
 
  /* Do not need to emit the label here.  We noted the existence of the
  /* Do not need to emit the label here.  We noted the existence of the
     label as a jump target in note_instructions; we'll emit the label
     label as a jump target in note_instructions; we'll emit the label
     for real at the beginning of the expand_byte_code loop.  */
     for real at the beginning of the expand_byte_code loop.  */
}
}
 
 
static void
static void
build_java_ret (tree location)
build_java_ret (tree location)
{
{
  java_add_stmt (build1 (GOTO_EXPR, void_type_node, location));
  java_add_stmt (build1 (GOTO_EXPR, void_type_node, location));
}
}
 
 
/* Implementation of operations on array: new, load, store, length */
/* Implementation of operations on array: new, load, store, length */
 
 
tree
tree
decode_newarray_type (int atype)
decode_newarray_type (int atype)
{
{
  switch (atype)
  switch (atype)
    {
    {
    case 4:  return boolean_type_node;
    case 4:  return boolean_type_node;
    case 5:  return char_type_node;
    case 5:  return char_type_node;
    case 6:  return float_type_node;
    case 6:  return float_type_node;
    case 7:  return double_type_node;
    case 7:  return double_type_node;
    case 8:  return byte_type_node;
    case 8:  return byte_type_node;
    case 9:  return short_type_node;
    case 9:  return short_type_node;
    case 10: return int_type_node;
    case 10: return int_type_node;
    case 11: return long_type_node;
    case 11: return long_type_node;
    default: return NULL_TREE;
    default: return NULL_TREE;
    }
    }
}
}
 
 
/* Map primitive type to the code used by OPCODE_newarray. */
/* Map primitive type to the code used by OPCODE_newarray. */
 
 
int
int
encode_newarray_type (tree type)
encode_newarray_type (tree type)
{
{
  if (type == boolean_type_node)
  if (type == boolean_type_node)
    return 4;
    return 4;
  else if (type == char_type_node)
  else if (type == char_type_node)
    return 5;
    return 5;
  else if (type == float_type_node)
  else if (type == float_type_node)
    return 6;
    return 6;
  else if (type == double_type_node)
  else if (type == double_type_node)
    return 7;
    return 7;
  else if (type == byte_type_node)
  else if (type == byte_type_node)
    return 8;
    return 8;
  else if (type == short_type_node)
  else if (type == short_type_node)
    return 9;
    return 9;
  else if (type == int_type_node)
  else if (type == int_type_node)
    return 10;
    return 10;
  else if (type == long_type_node)
  else if (type == long_type_node)
    return 11;
    return 11;
  else
  else
    gcc_unreachable ();
    gcc_unreachable ();
}
}
 
 
/* Build a call to _Jv_ThrowBadArrayIndex(), the
/* Build a call to _Jv_ThrowBadArrayIndex(), the
   ArrayIndexOfBoundsException exception handler.  */
   ArrayIndexOfBoundsException exception handler.  */
 
 
static tree
static tree
build_java_throw_out_of_bounds_exception (tree index)
build_java_throw_out_of_bounds_exception (tree index)
{
{
  tree node;
  tree node;
 
 
  /* We need to build a COMPOUND_EXPR because _Jv_ThrowBadArrayIndex()
  /* We need to build a COMPOUND_EXPR because _Jv_ThrowBadArrayIndex()
     has void return type.  We cannot just set the type of the CALL_EXPR below
     has void return type.  We cannot just set the type of the CALL_EXPR below
     to int_type_node because we would lose it during gimplification.  */
     to int_type_node because we would lose it during gimplification.  */
  gcc_assert (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (soft_badarrayindex_node))));
  gcc_assert (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (soft_badarrayindex_node))));
  node = build_call_nary (void_type_node,
  node = build_call_nary (void_type_node,
                               build_address_of (soft_badarrayindex_node),
                               build_address_of (soft_badarrayindex_node),
                               1, index);
                               1, index);
  TREE_SIDE_EFFECTS (node) = 1;
  TREE_SIDE_EFFECTS (node) = 1;
 
 
  node = build2 (COMPOUND_EXPR, int_type_node, node, integer_zero_node);
  node = build2 (COMPOUND_EXPR, int_type_node, node, integer_zero_node);
  TREE_SIDE_EFFECTS (node) = 1; /* Allows expansion within ANDIF */
  TREE_SIDE_EFFECTS (node) = 1; /* Allows expansion within ANDIF */
 
 
  return (node);
  return (node);
}
}
 
 
/* Return the length of an array. Doesn't perform any checking on the nature
/* Return the length of an array. Doesn't perform any checking on the nature
   or value of the array NODE. May be used to implement some bytecodes.  */
   or value of the array NODE. May be used to implement some bytecodes.  */
 
 
tree
tree
build_java_array_length_access (tree node)
build_java_array_length_access (tree node)
{
{
  tree type = TREE_TYPE (node);
  tree type = TREE_TYPE (node);
  tree array_type = TREE_TYPE (type);
  tree array_type = TREE_TYPE (type);
  HOST_WIDE_INT length;
  HOST_WIDE_INT length;
 
 
  if (!is_array_type_p (type))
  if (!is_array_type_p (type))
    {
    {
      /* With the new verifier, we will see an ordinary pointer type
      /* With the new verifier, we will see an ordinary pointer type
         here.  In this case, we just use an arbitrary array type.  */
         here.  In this case, we just use an arbitrary array type.  */
      array_type = build_java_array_type (object_ptr_type_node, -1);
      array_type = build_java_array_type (object_ptr_type_node, -1);
      type = promote_type (array_type);
      type = promote_type (array_type);
    }
    }
 
 
  length = java_array_type_length (type);
  length = java_array_type_length (type);
  if (length >= 0)
  if (length >= 0)
    return build_int_cst (NULL_TREE, length);
    return build_int_cst (NULL_TREE, length);
 
 
  node = build3 (COMPONENT_REF, int_type_node,
  node = build3 (COMPONENT_REF, int_type_node,
                 build_java_indirect_ref (array_type, node,
                 build_java_indirect_ref (array_type, node,
                                          flag_check_references),
                                          flag_check_references),
                 lookup_field (&array_type, get_identifier ("length")),
                 lookup_field (&array_type, get_identifier ("length")),
                 NULL_TREE);
                 NULL_TREE);
  IS_ARRAY_LENGTH_ACCESS (node) = 1;
  IS_ARRAY_LENGTH_ACCESS (node) = 1;
  return node;
  return node;
}
}
 
 
/* Optionally checks a reference against the NULL pointer.  ARG1: the
/* Optionally checks a reference against the NULL pointer.  ARG1: the
   expr, ARG2: we should check the reference.  Don't generate extra
   expr, ARG2: we should check the reference.  Don't generate extra
   checks if we're not generating code.  */
   checks if we're not generating code.  */
 
 
tree
tree
java_check_reference (tree expr, int check)
java_check_reference (tree expr, int check)
{
{
  if (!flag_syntax_only && check)
  if (!flag_syntax_only && check)
    {
    {
      expr = save_expr (expr);
      expr = save_expr (expr);
      expr = build3 (COND_EXPR, TREE_TYPE (expr),
      expr = build3 (COND_EXPR, TREE_TYPE (expr),
                     build2 (EQ_EXPR, boolean_type_node,
                     build2 (EQ_EXPR, boolean_type_node,
                             expr, null_pointer_node),
                             expr, null_pointer_node),
                     build_call_nary (void_type_node,
                     build_call_nary (void_type_node,
                                      build_address_of (soft_nullpointer_node),
                                      build_address_of (soft_nullpointer_node),
                                      0),
                                      0),
                     expr);
                     expr);
    }
    }
 
 
  return expr;
  return expr;
}
}
 
 
/* Reference an object: just like an INDIRECT_REF, but with checking.  */
/* Reference an object: just like an INDIRECT_REF, but with checking.  */
 
 
tree
tree
build_java_indirect_ref (tree type, tree expr, int check)
build_java_indirect_ref (tree type, tree expr, int check)
{
{
  tree t;
  tree t;
  t = java_check_reference (expr, check);
  t = java_check_reference (expr, check);
  t = convert (build_pointer_type (type), t);
  t = convert (build_pointer_type (type), t);
  return build1 (INDIRECT_REF, type, t);
  return build1 (INDIRECT_REF, type, t);
}
}
 
 
/* Implement array indexing (either as l-value or r-value).
/* Implement array indexing (either as l-value or r-value).
   Returns a tree for ARRAY[INDEX], assume TYPE is the element type.
   Returns a tree for ARRAY[INDEX], assume TYPE is the element type.
   Optionally performs bounds checking and/or test to NULL.
   Optionally performs bounds checking and/or test to NULL.
   At this point, ARRAY should have been verified as an array.  */
   At this point, ARRAY should have been verified as an array.  */
 
 
tree
tree
build_java_arrayaccess (tree array, tree type, tree index)
build_java_arrayaccess (tree array, tree type, tree index)
{
{
  tree node, throw_expr = NULL_TREE;
  tree node, throw_expr = NULL_TREE;
  tree data_field;
  tree data_field;
  tree ref;
  tree ref;
  tree array_type = TREE_TYPE (TREE_TYPE (array));
  tree array_type = TREE_TYPE (TREE_TYPE (array));
  tree size_exp = fold_convert (sizetype, size_in_bytes (type));
  tree size_exp = fold_convert (sizetype, size_in_bytes (type));
 
 
  if (!is_array_type_p (TREE_TYPE (array)))
  if (!is_array_type_p (TREE_TYPE (array)))
    {
    {
      /* With the new verifier, we will see an ordinary pointer type
      /* With the new verifier, we will see an ordinary pointer type
         here.  In this case, we just use the correct array type.  */
         here.  In this case, we just use the correct array type.  */
      array_type = build_java_array_type (type, -1);
      array_type = build_java_array_type (type, -1);
    }
    }
 
 
  if (flag_bounds_check)
  if (flag_bounds_check)
    {
    {
      /* Generate:
      /* Generate:
       * (unsigned jint) INDEX >= (unsigned jint) LEN
       * (unsigned jint) INDEX >= (unsigned jint) LEN
       *    && throw ArrayIndexOutOfBoundsException.
       *    && throw ArrayIndexOutOfBoundsException.
       * Note this is equivalent to and more efficient than:
       * Note this is equivalent to and more efficient than:
       * INDEX < 0 || INDEX >= LEN && throw ... */
       * INDEX < 0 || INDEX >= LEN && throw ... */
      tree test;
      tree test;
      tree len = convert (unsigned_int_type_node,
      tree len = convert (unsigned_int_type_node,
                          build_java_array_length_access (array));
                          build_java_array_length_access (array));
      test = fold_build2 (GE_EXPR, boolean_type_node,
      test = fold_build2 (GE_EXPR, boolean_type_node,
                          convert (unsigned_int_type_node, index),
                          convert (unsigned_int_type_node, index),
                          len);
                          len);
      if (! integer_zerop (test))
      if (! integer_zerop (test))
        {
        {
          throw_expr
          throw_expr
            = build2 (TRUTH_ANDIF_EXPR, int_type_node, test,
            = build2 (TRUTH_ANDIF_EXPR, int_type_node, test,
                      build_java_throw_out_of_bounds_exception (index));
                      build_java_throw_out_of_bounds_exception (index));
          /* allows expansion within COMPOUND */
          /* allows expansion within COMPOUND */
          TREE_SIDE_EFFECTS( throw_expr ) = 1;
          TREE_SIDE_EFFECTS( throw_expr ) = 1;
        }
        }
    }
    }
 
 
  /* If checking bounds, wrap the index expr with a COMPOUND_EXPR in order
  /* If checking bounds, wrap the index expr with a COMPOUND_EXPR in order
     to have the bounds check evaluated first. */
     to have the bounds check evaluated first. */
  if (throw_expr != NULL_TREE)
  if (throw_expr != NULL_TREE)
    index = build2 (COMPOUND_EXPR, int_type_node, throw_expr, index);
    index = build2 (COMPOUND_EXPR, int_type_node, throw_expr, index);
 
 
  data_field = lookup_field (&array_type, get_identifier ("data"));
  data_field = lookup_field (&array_type, get_identifier ("data"));
 
 
  ref = build3 (COMPONENT_REF, TREE_TYPE (data_field),
  ref = build3 (COMPONENT_REF, TREE_TYPE (data_field),
                build_java_indirect_ref (array_type, array,
                build_java_indirect_ref (array_type, array,
                                         flag_check_references),
                                         flag_check_references),
                data_field, NULL_TREE);
                data_field, NULL_TREE);
 
 
  /* Take the address of the data field and convert it to a pointer to
  /* Take the address of the data field and convert it to a pointer to
     the element type.  */
     the element type.  */
  node = build1 (NOP_EXPR, build_pointer_type (type), build_address_of (ref));
  node = build1 (NOP_EXPR, build_pointer_type (type), build_address_of (ref));
 
 
  /* Multiply the index by the size of an element to obtain a byte
  /* Multiply the index by the size of an element to obtain a byte
     offset.  Convert the result to a pointer to the element type.  */
     offset.  Convert the result to a pointer to the element type.  */
  index = build2 (MULT_EXPR, sizetype,
  index = build2 (MULT_EXPR, sizetype,
                  fold_convert (sizetype, index),
                  fold_convert (sizetype, index),
                  size_exp);
                  size_exp);
 
 
  /* Sum the byte offset and the address of the data field.  */
  /* Sum the byte offset and the address of the data field.  */
  node = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (node), node, index);
  node = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (node), node, index);
 
 
  /* Finally, return
  /* Finally, return
 
 
    *((&array->data) + index*size_exp)
    *((&array->data) + index*size_exp)
 
 
  */
  */
  return build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (node)), node);
  return build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (node)), node);
}
}
 
 
/* Generate code to throw an ArrayStoreException if OBJECT is not assignable
/* Generate code to throw an ArrayStoreException if OBJECT is not assignable
   (at runtime) to an element of ARRAY.  A NOP_EXPR is returned if it can
   (at runtime) to an element of ARRAY.  A NOP_EXPR is returned if it can
   determine that no check is required. */
   determine that no check is required. */
 
 
tree
tree
build_java_arraystore_check (tree array, tree object)
build_java_arraystore_check (tree array, tree object)
{
{
  tree check, element_type, source;
  tree check, element_type, source;
  tree array_type_p = TREE_TYPE (array);
  tree array_type_p = TREE_TYPE (array);
  tree object_type = TYPE_NAME (TREE_TYPE (TREE_TYPE (object)));
  tree object_type = TYPE_NAME (TREE_TYPE (TREE_TYPE (object)));
 
 
  if (! flag_verify_invocations)
  if (! flag_verify_invocations)
    {
    {
      /* With the new verifier, we don't track precise types.  FIXME:
      /* With the new verifier, we don't track precise types.  FIXME:
         performance regression here.  */
         performance regression here.  */
      element_type = TYPE_NAME (object_type_node);
      element_type = TYPE_NAME (object_type_node);
    }
    }
  else
  else
    {
    {
      gcc_assert (is_array_type_p (array_type_p));
      gcc_assert (is_array_type_p (array_type_p));
 
 
      /* Get the TYPE_DECL for ARRAY's element type. */
      /* Get the TYPE_DECL for ARRAY's element type. */
      element_type
      element_type
        = TYPE_NAME (TREE_TYPE (TREE_TYPE (TREE_TYPE (array_type_p))));
        = TYPE_NAME (TREE_TYPE (TREE_TYPE (TREE_TYPE (array_type_p))));
    }
    }
 
 
  gcc_assert (TREE_CODE (element_type) == TYPE_DECL
  gcc_assert (TREE_CODE (element_type) == TYPE_DECL
              && TREE_CODE (object_type) == TYPE_DECL);
              && TREE_CODE (object_type) == TYPE_DECL);
 
 
  if (!flag_store_check)
  if (!flag_store_check)
    return build1 (NOP_EXPR, array_type_p, array);
    return build1 (NOP_EXPR, array_type_p, array);
 
 
  /* No check is needed if the element type is final.  Also check that
  /* No check is needed if the element type is final.  Also check that
     element_type matches object_type, since in the bytecode
     element_type matches object_type, since in the bytecode
     compilation case element_type may be the actual element type of
     compilation case element_type may be the actual element type of
     the array rather than its declared type.  However, if we're doing
     the array rather than its declared type.  However, if we're doing
     indirect dispatch, we can't do the `final' optimization.  */
     indirect dispatch, we can't do the `final' optimization.  */
  if (element_type == object_type
  if (element_type == object_type
      && ! flag_indirect_dispatch
      && ! flag_indirect_dispatch
      && CLASS_FINAL (element_type))
      && CLASS_FINAL (element_type))
    return build1 (NOP_EXPR, array_type_p, array);
    return build1 (NOP_EXPR, array_type_p, array);
 
 
  /* OBJECT might be wrapped by a SAVE_EXPR. */
  /* OBJECT might be wrapped by a SAVE_EXPR. */
  if (TREE_CODE (object) == SAVE_EXPR)
  if (TREE_CODE (object) == SAVE_EXPR)
    source = TREE_OPERAND (object, 0);
    source = TREE_OPERAND (object, 0);
  else
  else
    source = object;
    source = object;
 
 
  /* Avoid the check if OBJECT was just loaded from the same array. */
  /* Avoid the check if OBJECT was just loaded from the same array. */
  if (TREE_CODE (source) == ARRAY_REF)
  if (TREE_CODE (source) == ARRAY_REF)
    {
    {
      tree target;
      tree target;
      source = TREE_OPERAND (source, 0); /* COMPONENT_REF. */
      source = TREE_OPERAND (source, 0); /* COMPONENT_REF. */
      source = TREE_OPERAND (source, 0); /* INDIRECT_REF. */
      source = TREE_OPERAND (source, 0); /* INDIRECT_REF. */
      source = TREE_OPERAND (source, 0); /* Source array's DECL or SAVE_EXPR. */
      source = TREE_OPERAND (source, 0); /* Source array's DECL or SAVE_EXPR. */
      if (TREE_CODE (source) == SAVE_EXPR)
      if (TREE_CODE (source) == SAVE_EXPR)
        source = TREE_OPERAND (source, 0);
        source = TREE_OPERAND (source, 0);
 
 
      target = array;
      target = array;
      if (TREE_CODE (target) == SAVE_EXPR)
      if (TREE_CODE (target) == SAVE_EXPR)
        target = TREE_OPERAND (target, 0);
        target = TREE_OPERAND (target, 0);
 
 
      if (source == target)
      if (source == target)
        return build1 (NOP_EXPR, array_type_p, array);
        return build1 (NOP_EXPR, array_type_p, array);
    }
    }
 
 
  /* Build an invocation of _Jv_CheckArrayStore */
  /* Build an invocation of _Jv_CheckArrayStore */
  check = build_call_nary (void_type_node,
  check = build_call_nary (void_type_node,
                           build_address_of (soft_checkarraystore_node),
                           build_address_of (soft_checkarraystore_node),
                           2, array, object);
                           2, array, object);
  TREE_SIDE_EFFECTS (check) = 1;
  TREE_SIDE_EFFECTS (check) = 1;
 
 
  return check;
  return check;
}
}
 
 
/* Makes sure that INDEXED_TYPE is appropriate. If not, make it from
/* Makes sure that INDEXED_TYPE is appropriate. If not, make it from
   ARRAY_NODE. This function is used to retrieve something less vague than
   ARRAY_NODE. This function is used to retrieve something less vague than
   a pointer type when indexing the first dimension of something like [[<t>.
   a pointer type when indexing the first dimension of something like [[<t>.
   May return a corrected type, if necessary, otherwise INDEXED_TYPE is
   May return a corrected type, if necessary, otherwise INDEXED_TYPE is
   return unchanged.  */
   return unchanged.  */
 
 
static tree
static tree
build_java_check_indexed_type (tree array_node ATTRIBUTE_UNUSED,
build_java_check_indexed_type (tree array_node ATTRIBUTE_UNUSED,
                               tree indexed_type)
                               tree indexed_type)
{
{
  /* We used to check to see if ARRAY_NODE really had array type.
  /* We used to check to see if ARRAY_NODE really had array type.
     However, with the new verifier, this is not necessary, as we know
     However, with the new verifier, this is not necessary, as we know
     that the object will be an array of the appropriate type.  */
     that the object will be an array of the appropriate type.  */
 
 
  return indexed_type;
  return indexed_type;
}
}
 
 
/* newarray triggers a call to _Jv_NewPrimArray. This function should be
/* newarray triggers a call to _Jv_NewPrimArray. This function should be
   called with an integer code (the type of array to create), and the length
   called with an integer code (the type of array to create), and the length
   of the array to create.  */
   of the array to create.  */
 
 
tree
tree
build_newarray (int atype_value, tree length)
build_newarray (int atype_value, tree length)
{
{
  tree type_arg;
  tree type_arg;
 
 
  tree prim_type = decode_newarray_type (atype_value);
  tree prim_type = decode_newarray_type (atype_value);
  tree type
  tree type
    = build_java_array_type (prim_type,
    = build_java_array_type (prim_type,
                             host_integerp (length, 0) == INTEGER_CST
                             host_integerp (length, 0) == INTEGER_CST
                             ? tree_low_cst (length, 0) : -1);
                             ? tree_low_cst (length, 0) : -1);
 
 
  /* Pass a reference to the primitive type class and save the runtime
  /* Pass a reference to the primitive type class and save the runtime
     some work.  */
     some work.  */
  type_arg = build_class_ref (prim_type);
  type_arg = build_class_ref (prim_type);
 
 
  return build_call_nary (promote_type (type),
  return build_call_nary (promote_type (type),
                          build_address_of (soft_newarray_node),
                          build_address_of (soft_newarray_node),
                          2, type_arg, length);
                          2, type_arg, length);
}
}
 
 
/* Generates anewarray from a given CLASS_TYPE. Gets from the stack the size
/* Generates anewarray from a given CLASS_TYPE. Gets from the stack the size
   of the dimension. */
   of the dimension. */
 
 
tree
tree
build_anewarray (tree class_type, tree length)
build_anewarray (tree class_type, tree length)
{
{
  tree type
  tree type
    = build_java_array_type (class_type,
    = build_java_array_type (class_type,
                             host_integerp (length, 0)
                             host_integerp (length, 0)
                             ? tree_low_cst (length, 0) : -1);
                             ? tree_low_cst (length, 0) : -1);
 
 
  return build_call_nary (promote_type (type),
  return build_call_nary (promote_type (type),
                          build_address_of (soft_anewarray_node),
                          build_address_of (soft_anewarray_node),
                          3,
                          3,
                          length,
                          length,
                          build_class_ref (class_type),
                          build_class_ref (class_type),
                          null_pointer_node);
                          null_pointer_node);
}
}
 
 
/* Return a node the evaluates 'new TYPE[LENGTH]'. */
/* Return a node the evaluates 'new TYPE[LENGTH]'. */
 
 
tree
tree
build_new_array (tree type, tree length)
build_new_array (tree type, tree length)
{
{
  if (JPRIMITIVE_TYPE_P (type))
  if (JPRIMITIVE_TYPE_P (type))
    return build_newarray (encode_newarray_type (type), length);
    return build_newarray (encode_newarray_type (type), length);
  else
  else
    return build_anewarray (TREE_TYPE (type), length);
    return build_anewarray (TREE_TYPE (type), length);
}
}
 
 
/* Generates a call to _Jv_NewMultiArray. multianewarray expects a
/* Generates a call to _Jv_NewMultiArray. multianewarray expects a
   class pointer, a number of dimensions and the matching number of
   class pointer, a number of dimensions and the matching number of
   dimensions. The argument list is NULL terminated.  */
   dimensions. The argument list is NULL terminated.  */
 
 
static void
static void
expand_java_multianewarray (tree class_type, int ndim)
expand_java_multianewarray (tree class_type, int ndim)
{
{
  int i;
  int i;
  tree args = build_tree_list( NULL_TREE, null_pointer_node );
  tree args = build_tree_list( NULL_TREE, null_pointer_node );
 
 
  for( i = 0; i < ndim; i++ )
  for( i = 0; i < ndim; i++ )
    args = tree_cons (NULL_TREE, pop_value (int_type_node), args);
    args = tree_cons (NULL_TREE, pop_value (int_type_node), args);
 
 
  args = tree_cons (NULL_TREE,
  args = tree_cons (NULL_TREE,
                    build_class_ref (class_type),
                    build_class_ref (class_type),
                    tree_cons (NULL_TREE,
                    tree_cons (NULL_TREE,
                               build_int_cst (NULL_TREE, ndim),
                               build_int_cst (NULL_TREE, ndim),
                               args));
                               args));
 
 
  push_value (build_call_list (promote_type (class_type),
  push_value (build_call_list (promote_type (class_type),
                               build_address_of (soft_multianewarray_node),
                               build_address_of (soft_multianewarray_node),
                               args));
                               args));
}
}
 
 
/*  ARRAY[INDEX] <- RHS. build_java_check_indexed_type makes sure that
/*  ARRAY[INDEX] <- RHS. build_java_check_indexed_type makes sure that
    ARRAY is an array type. May expand some bound checking and NULL
    ARRAY is an array type. May expand some bound checking and NULL
    pointer checking. RHS_TYPE_NODE we are going to store. In the case
    pointer checking. RHS_TYPE_NODE we are going to store. In the case
    of the CHAR/BYTE/BOOLEAN SHORT, the type popped of the stack is an
    of the CHAR/BYTE/BOOLEAN SHORT, the type popped of the stack is an
    INT. In those cases, we make the conversion.
    INT. In those cases, we make the conversion.
 
 
    if ARRAy is a reference type, the assignment is checked at run-time
    if ARRAy is a reference type, the assignment is checked at run-time
    to make sure that the RHS can be assigned to the array element
    to make sure that the RHS can be assigned to the array element
    type. It is not necessary to generate this code if ARRAY is final.  */
    type. It is not necessary to generate this code if ARRAY is final.  */
 
 
static void
static void
expand_java_arraystore (tree rhs_type_node)
expand_java_arraystore (tree rhs_type_node)
{
{
  tree rhs_node    = pop_value ((INTEGRAL_TYPE_P (rhs_type_node)
  tree rhs_node    = pop_value ((INTEGRAL_TYPE_P (rhs_type_node)
                                 && TYPE_PRECISION (rhs_type_node) <= 32) ?
                                 && TYPE_PRECISION (rhs_type_node) <= 32) ?
                                 int_type_node : rhs_type_node);
                                 int_type_node : rhs_type_node);
  tree index = pop_value (int_type_node);
  tree index = pop_value (int_type_node);
  tree array_type, array, temp, access;
  tree array_type, array, temp, access;
 
 
  /* If we're processing an `aaload' we might as well just pick
  /* If we're processing an `aaload' we might as well just pick
     `Object'.  */
     `Object'.  */
  if (TREE_CODE (rhs_type_node) == POINTER_TYPE)
  if (TREE_CODE (rhs_type_node) == POINTER_TYPE)
    {
    {
      array_type = build_java_array_type (object_ptr_type_node, -1);
      array_type = build_java_array_type (object_ptr_type_node, -1);
      rhs_type_node = object_ptr_type_node;
      rhs_type_node = object_ptr_type_node;
    }
    }
  else
  else
    array_type = build_java_array_type (rhs_type_node, -1);
    array_type = build_java_array_type (rhs_type_node, -1);
 
 
  array = pop_value (array_type);
  array = pop_value (array_type);
  array = build1 (NOP_EXPR, promote_type (array_type), array);
  array = build1 (NOP_EXPR, promote_type (array_type), array);
 
 
  rhs_type_node    = build_java_check_indexed_type (array, rhs_type_node);
  rhs_type_node    = build_java_check_indexed_type (array, rhs_type_node);
 
 
  flush_quick_stack ();
  flush_quick_stack ();
 
 
  index = save_expr (index);
  index = save_expr (index);
  array = save_expr (array);
  array = save_expr (array);
 
 
  /* We want to perform the bounds check (done by
  /* We want to perform the bounds check (done by
     build_java_arrayaccess) before the type check (done by
     build_java_arrayaccess) before the type check (done by
     build_java_arraystore_check).  So, we call build_java_arrayaccess
     build_java_arraystore_check).  So, we call build_java_arrayaccess
     -- which returns an ARRAY_REF lvalue -- and we then generate code
     -- which returns an ARRAY_REF lvalue -- and we then generate code
     to stash the address of that lvalue in a temp.  Then we call
     to stash the address of that lvalue in a temp.  Then we call
     build_java_arraystore_check, and finally we generate a
     build_java_arraystore_check, and finally we generate a
     MODIFY_EXPR to set the array element.  */
     MODIFY_EXPR to set the array element.  */
 
 
  access = build_java_arrayaccess (array, rhs_type_node, index);
  access = build_java_arrayaccess (array, rhs_type_node, index);
  temp = build_decl (input_location, VAR_DECL, NULL_TREE,
  temp = build_decl (input_location, VAR_DECL, NULL_TREE,
                     build_pointer_type (TREE_TYPE (access)));
                     build_pointer_type (TREE_TYPE (access)));
  java_add_local_var (temp);
  java_add_local_var (temp);
  java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (temp),
  java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (temp),
                         temp,
                         temp,
                         build_fold_addr_expr (access)));
                         build_fold_addr_expr (access)));
 
 
  if (TREE_CODE (rhs_type_node) == POINTER_TYPE)
  if (TREE_CODE (rhs_type_node) == POINTER_TYPE)
    {
    {
      tree check = build_java_arraystore_check (array, rhs_node);
      tree check = build_java_arraystore_check (array, rhs_node);
      java_add_stmt (check);
      java_add_stmt (check);
    }
    }
 
 
  java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (access),
  java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (access),
                         build1 (INDIRECT_REF, TREE_TYPE (access), temp),
                         build1 (INDIRECT_REF, TREE_TYPE (access), temp),
                         rhs_node));
                         rhs_node));
}
}
 
 
/* Expand the evaluation of ARRAY[INDEX]. build_java_check_indexed_type makes
/* Expand the evaluation of ARRAY[INDEX]. build_java_check_indexed_type makes
   sure that LHS is an array type. May expand some bound checking and NULL
   sure that LHS is an array type. May expand some bound checking and NULL
   pointer checking.
   pointer checking.
   LHS_TYPE_NODE is the type of ARRAY[INDEX]. But in the case of CHAR/BYTE/
   LHS_TYPE_NODE is the type of ARRAY[INDEX]. But in the case of CHAR/BYTE/
   BOOLEAN/SHORT, we push a promoted type back to the stack.
   BOOLEAN/SHORT, we push a promoted type back to the stack.
*/
*/
 
 
static void
static void
expand_java_arrayload (tree lhs_type_node)
expand_java_arrayload (tree lhs_type_node)
{
{
  tree load_node;
  tree load_node;
  tree index_node = pop_value (int_type_node);
  tree index_node = pop_value (int_type_node);
  tree array_type;
  tree array_type;
  tree array_node;
  tree array_node;
 
 
  /* If we're processing an `aaload' we might as well just pick
  /* If we're processing an `aaload' we might as well just pick
     `Object'.  */
     `Object'.  */
  if (TREE_CODE (lhs_type_node) == POINTER_TYPE)
  if (TREE_CODE (lhs_type_node) == POINTER_TYPE)
    {
    {
      array_type = build_java_array_type (object_ptr_type_node, -1);
      array_type = build_java_array_type (object_ptr_type_node, -1);
      lhs_type_node = object_ptr_type_node;
      lhs_type_node = object_ptr_type_node;
    }
    }
  else
  else
    array_type = build_java_array_type (lhs_type_node, -1);
    array_type = build_java_array_type (lhs_type_node, -1);
  array_node = pop_value (array_type);
  array_node = pop_value (array_type);
  array_node = build1 (NOP_EXPR, promote_type (array_type), array_node);
  array_node = build1 (NOP_EXPR, promote_type (array_type), array_node);
 
 
  index_node = save_expr (index_node);
  index_node = save_expr (index_node);
  array_node = save_expr (array_node);
  array_node = save_expr (array_node);
 
 
  lhs_type_node = build_java_check_indexed_type (array_node,
  lhs_type_node = build_java_check_indexed_type (array_node,
                                                 lhs_type_node);
                                                 lhs_type_node);
  load_node = build_java_arrayaccess (array_node,
  load_node = build_java_arrayaccess (array_node,
                                      lhs_type_node,
                                      lhs_type_node,
                                      index_node);
                                      index_node);
  if (INTEGRAL_TYPE_P (lhs_type_node) && TYPE_PRECISION (lhs_type_node) <= 32)
  if (INTEGRAL_TYPE_P (lhs_type_node) && TYPE_PRECISION (lhs_type_node) <= 32)
    load_node = fold_build1 (NOP_EXPR, int_type_node, load_node);
    load_node = fold_build1 (NOP_EXPR, int_type_node, load_node);
  push_value (load_node);
  push_value (load_node);
}
}
 
 
/* Expands .length. Makes sure that we deal with and array and may expand
/* Expands .length. Makes sure that we deal with and array and may expand
   a NULL check on the array object.  */
   a NULL check on the array object.  */
 
 
static void
static void
expand_java_array_length (void)
expand_java_array_length (void)
{
{
  tree array  = pop_value (ptr_type_node);
  tree array  = pop_value (ptr_type_node);
  tree length = build_java_array_length_access (array);
  tree length = build_java_array_length_access (array);
 
 
  push_value (length);
  push_value (length);
}
}
 
 
/* Emit code for the call to _Jv_Monitor{Enter,Exit}. CALL can be
/* Emit code for the call to _Jv_Monitor{Enter,Exit}. CALL can be
   either soft_monitorenter_node or soft_monitorexit_node.  */
   either soft_monitorenter_node or soft_monitorexit_node.  */
 
 
static tree
static tree
build_java_monitor (tree call, tree object)
build_java_monitor (tree call, tree object)
{
{
  return build_call_nary (void_type_node,
  return build_call_nary (void_type_node,
                          build_address_of (call),
                          build_address_of (call),
                          1, object);
                          1, object);
}
}
 
 
/* Emit code for one of the PUSHC instructions. */
/* Emit code for one of the PUSHC instructions. */
 
 
static void
static void
expand_java_pushc (int ival, tree type)
expand_java_pushc (int ival, tree type)
{
{
  tree value;
  tree value;
  if (type == ptr_type_node && ival == 0)
  if (type == ptr_type_node && ival == 0)
    value = null_pointer_node;
    value = null_pointer_node;
  else if (type == int_type_node || type == long_type_node)
  else if (type == int_type_node || type == long_type_node)
    value = build_int_cst (type, ival);
    value = build_int_cst (type, ival);
  else if (type == float_type_node || type == double_type_node)
  else if (type == float_type_node || type == double_type_node)
    {
    {
      REAL_VALUE_TYPE x;
      REAL_VALUE_TYPE x;
      REAL_VALUE_FROM_INT (x, ival, 0, TYPE_MODE (type));
      REAL_VALUE_FROM_INT (x, ival, 0, TYPE_MODE (type));
      value = build_real (type, x);
      value = build_real (type, x);
    }
    }
  else
  else
    gcc_unreachable ();
    gcc_unreachable ();
 
 
  push_value (value);
  push_value (value);
}
}
 
 
static void
static void
expand_java_return (tree type)
expand_java_return (tree type)
{
{
  if (type == void_type_node)
  if (type == void_type_node)
    java_add_stmt (build1 (RETURN_EXPR, void_type_node, NULL));
    java_add_stmt (build1 (RETURN_EXPR, void_type_node, NULL));
  else
  else
    {
    {
      tree retval = pop_value (type);
      tree retval = pop_value (type);
      tree res = DECL_RESULT (current_function_decl);
      tree res = DECL_RESULT (current_function_decl);
      retval = build2 (MODIFY_EXPR, TREE_TYPE (res), res, retval);
      retval = build2 (MODIFY_EXPR, TREE_TYPE (res), res, retval);
 
 
      /* Handle the situation where the native integer type is smaller
      /* Handle the situation where the native integer type is smaller
         than the JVM integer. It can happen for many cross compilers.
         than the JVM integer. It can happen for many cross compilers.
         The whole if expression just goes away if INT_TYPE_SIZE < 32
         The whole if expression just goes away if INT_TYPE_SIZE < 32
         is false. */
         is false. */
      if (INT_TYPE_SIZE < 32
      if (INT_TYPE_SIZE < 32
          && (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (res)))
          && (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (res)))
              < GET_MODE_SIZE (TYPE_MODE (type))))
              < GET_MODE_SIZE (TYPE_MODE (type))))
        retval = build1(NOP_EXPR, TREE_TYPE(res), retval);
        retval = build1(NOP_EXPR, TREE_TYPE(res), retval);
 
 
      TREE_SIDE_EFFECTS (retval) = 1;
      TREE_SIDE_EFFECTS (retval) = 1;
      java_add_stmt (build1 (RETURN_EXPR, void_type_node, retval));
      java_add_stmt (build1 (RETURN_EXPR, void_type_node, retval));
    }
    }
}
}
 
 
static void
static void
expand_load_internal (int index, tree type, int pc)
expand_load_internal (int index, tree type, int pc)
{
{
  tree copy;
  tree copy;
  tree var = find_local_variable (index, type, pc);
  tree var = find_local_variable (index, type, pc);
 
 
  /* Now VAR is the VAR_DECL (or PARM_DECL) that we are going to push
  /* Now VAR is the VAR_DECL (or PARM_DECL) that we are going to push
     on the stack.  If there is an assignment to this VAR_DECL between
     on the stack.  If there is an assignment to this VAR_DECL between
     the stack push and the use, then the wrong code could be
     the stack push and the use, then the wrong code could be
     generated.  To avoid this we create a new local and copy our
     generated.  To avoid this we create a new local and copy our
     value into it.  Then we push this new local on the stack.
     value into it.  Then we push this new local on the stack.
     Hopefully this all gets optimized out.  */
     Hopefully this all gets optimized out.  */
  copy = build_decl (input_location, VAR_DECL, NULL_TREE, type);
  copy = build_decl (input_location, VAR_DECL, NULL_TREE, type);
  if ((INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))
  if ((INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))
      && TREE_TYPE (copy) != TREE_TYPE (var))
      && TREE_TYPE (copy) != TREE_TYPE (var))
    var = convert (type, var);
    var = convert (type, var);
  java_add_local_var (copy);
  java_add_local_var (copy);
  java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (var), copy, var));
  java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (var), copy, var));
 
 
  push_value (copy);
  push_value (copy);
}
}
 
 
tree
tree
build_address_of (tree value)
build_address_of (tree value)
{
{
  return build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (value)), value);
  return build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (value)), value);
}
}
 
 
bool
bool
class_has_finalize_method (tree type)
class_has_finalize_method (tree type)
{
{
  tree super = CLASSTYPE_SUPER (type);
  tree super = CLASSTYPE_SUPER (type);
 
 
  if (super == NULL_TREE)
  if (super == NULL_TREE)
    return false;       /* Every class with a real finalizer inherits   */
    return false;       /* Every class with a real finalizer inherits   */
                        /* from java.lang.Object.                       */
                        /* from java.lang.Object.                       */
  else
  else
    return HAS_FINALIZER_P (type) || class_has_finalize_method (super);
    return HAS_FINALIZER_P (type) || class_has_finalize_method (super);
}
}
 
 
tree
tree
java_create_object (tree type)
java_create_object (tree type)
{
{
  tree alloc_node = (class_has_finalize_method (type)
  tree alloc_node = (class_has_finalize_method (type)
                     ? alloc_object_node
                     ? alloc_object_node
                     : alloc_no_finalizer_node);
                     : alloc_no_finalizer_node);
 
 
  return build_call_nary (promote_type (type),
  return build_call_nary (promote_type (type),
                          build_address_of (alloc_node),
                          build_address_of (alloc_node),
                          1, build_class_ref (type));
                          1, build_class_ref (type));
}
}
 
 
static void
static void
expand_java_NEW (tree type)
expand_java_NEW (tree type)
{
{
  tree alloc_node;
  tree alloc_node;
 
 
  alloc_node = (class_has_finalize_method (type) ? alloc_object_node
  alloc_node = (class_has_finalize_method (type) ? alloc_object_node
                                                 : alloc_no_finalizer_node);
                                                 : alloc_no_finalizer_node);
  if (! CLASS_LOADED_P (type))
  if (! CLASS_LOADED_P (type))
    load_class (type, 1);
    load_class (type, 1);
  safe_layout_class (type);
  safe_layout_class (type);
  push_value (build_call_nary (promote_type (type),
  push_value (build_call_nary (promote_type (type),
                               build_address_of (alloc_node),
                               build_address_of (alloc_node),
                               1, build_class_ref (type)));
                               1, build_class_ref (type)));
}
}
 
 
/* This returns an expression which will extract the class of an
/* This returns an expression which will extract the class of an
   object.  */
   object.  */
 
 
tree
tree
build_get_class (tree value)
build_get_class (tree value)
{
{
  tree class_field = lookup_field (&dtable_type, get_identifier ("class"));
  tree class_field = lookup_field (&dtable_type, get_identifier ("class"));
  tree vtable_field = lookup_field (&object_type_node,
  tree vtable_field = lookup_field (&object_type_node,
                                    get_identifier ("vtable"));
                                    get_identifier ("vtable"));
  tree tmp = build3 (COMPONENT_REF, dtable_ptr_type,
  tree tmp = build3 (COMPONENT_REF, dtable_ptr_type,
                     build_java_indirect_ref (object_type_node, value,
                     build_java_indirect_ref (object_type_node, value,
                                              flag_check_references),
                                              flag_check_references),
                     vtable_field, NULL_TREE);
                     vtable_field, NULL_TREE);
  return build3 (COMPONENT_REF, class_ptr_type,
  return build3 (COMPONENT_REF, class_ptr_type,
                 build1 (INDIRECT_REF, dtable_type, tmp),
                 build1 (INDIRECT_REF, dtable_type, tmp),
                 class_field, NULL_TREE);
                 class_field, NULL_TREE);
}
}
 
 
/* This builds the tree representation of the `instanceof' operator.
/* This builds the tree representation of the `instanceof' operator.
   It tries various tricks to optimize this in cases where types are
   It tries various tricks to optimize this in cases where types are
   known.  */
   known.  */
 
 
tree
tree
build_instanceof (tree value, tree type)
build_instanceof (tree value, tree type)
{
{
  tree expr;
  tree expr;
  tree itype = TREE_TYPE (TREE_TYPE (soft_instanceof_node));
  tree itype = TREE_TYPE (TREE_TYPE (soft_instanceof_node));
  tree valtype = TREE_TYPE (TREE_TYPE (value));
  tree valtype = TREE_TYPE (TREE_TYPE (value));
  tree valclass = TYPE_NAME (valtype);
  tree valclass = TYPE_NAME (valtype);
  tree klass;
  tree klass;
 
 
  /* When compiling from bytecode, we need to ensure that TYPE has
  /* When compiling from bytecode, we need to ensure that TYPE has
     been loaded.  */
     been loaded.  */
  if (CLASS_P (type) && ! CLASS_LOADED_P (type))
  if (CLASS_P (type) && ! CLASS_LOADED_P (type))
    {
    {
      load_class (type, 1);
      load_class (type, 1);
      safe_layout_class (type);
      safe_layout_class (type);
      if (! TYPE_SIZE (type) || TREE_CODE (TYPE_SIZE (type)) == ERROR_MARK)
      if (! TYPE_SIZE (type) || TREE_CODE (TYPE_SIZE (type)) == ERROR_MARK)
        return error_mark_node;
        return error_mark_node;
    }
    }
  klass = TYPE_NAME (type);
  klass = TYPE_NAME (type);
 
 
  if (type == object_type_node || inherits_from_p (valtype, type))
  if (type == object_type_node || inherits_from_p (valtype, type))
    {
    {
      /* Anything except `null' is an instance of Object.  Likewise,
      /* Anything except `null' is an instance of Object.  Likewise,
         if the object is known to be an instance of the class, then
         if the object is known to be an instance of the class, then
         we only need to check for `null'.  */
         we only need to check for `null'.  */
      expr = build2 (NE_EXPR, itype, value, null_pointer_node);
      expr = build2 (NE_EXPR, itype, value, null_pointer_node);
    }
    }
  else if (flag_verify_invocations
  else if (flag_verify_invocations
           && ! TYPE_ARRAY_P (type)
           && ! TYPE_ARRAY_P (type)
           && ! TYPE_ARRAY_P (valtype)
           && ! TYPE_ARRAY_P (valtype)
           && DECL_P (klass) && DECL_P (valclass)
           && DECL_P (klass) && DECL_P (valclass)
           && ! CLASS_INTERFACE (valclass)
           && ! CLASS_INTERFACE (valclass)
           && ! CLASS_INTERFACE (klass)
           && ! CLASS_INTERFACE (klass)
           && ! inherits_from_p (type, valtype)
           && ! inherits_from_p (type, valtype)
           && (CLASS_FINAL (klass)
           && (CLASS_FINAL (klass)
               || ! inherits_from_p (valtype, type)))
               || ! inherits_from_p (valtype, type)))
    {
    {
      /* The classes are from different branches of the derivation
      /* The classes are from different branches of the derivation
         tree, so we immediately know the answer.  */
         tree, so we immediately know the answer.  */
      expr = boolean_false_node;
      expr = boolean_false_node;
    }
    }
  else if (DECL_P (klass) && CLASS_FINAL (klass))
  else if (DECL_P (klass) && CLASS_FINAL (klass))
    {
    {
      tree save = save_expr (value);
      tree save = save_expr (value);
      expr = build3 (COND_EXPR, itype,
      expr = build3 (COND_EXPR, itype,
                     build2 (NE_EXPR, boolean_type_node,
                     build2 (NE_EXPR, boolean_type_node,
                             save, null_pointer_node),
                             save, null_pointer_node),
                     build2 (EQ_EXPR, itype,
                     build2 (EQ_EXPR, itype,
                             build_get_class (save),
                             build_get_class (save),
                             build_class_ref (type)),
                             build_class_ref (type)),
                     boolean_false_node);
                     boolean_false_node);
    }
    }
  else
  else
    {
    {
      expr = build_call_nary (itype,
      expr = build_call_nary (itype,
                              build_address_of (soft_instanceof_node),
                              build_address_of (soft_instanceof_node),
                              2, value, build_class_ref (type));
                              2, value, build_class_ref (type));
    }
    }
  TREE_SIDE_EFFECTS (expr) = TREE_SIDE_EFFECTS (value);
  TREE_SIDE_EFFECTS (expr) = TREE_SIDE_EFFECTS (value);
  return expr;
  return expr;
}
}
 
 
static void
static void
expand_java_INSTANCEOF (tree type)
expand_java_INSTANCEOF (tree type)
{
{
  tree value = pop_value (object_ptr_type_node);
  tree value = pop_value (object_ptr_type_node);
  value = build_instanceof (value, type);
  value = build_instanceof (value, type);
  push_value (value);
  push_value (value);
}
}
 
 
static void
static void
expand_java_CHECKCAST (tree type)
expand_java_CHECKCAST (tree type)
{
{
  tree value = pop_value (ptr_type_node);
  tree value = pop_value (ptr_type_node);
  value = build_call_nary (promote_type (type),
  value = build_call_nary (promote_type (type),
                           build_address_of (soft_checkcast_node),
                           build_address_of (soft_checkcast_node),
                           2, build_class_ref (type), value);
                           2, build_class_ref (type), value);
  push_value (value);
  push_value (value);
}
}
 
 
static void
static void
expand_iinc (unsigned int local_var_index, int ival, int pc)
expand_iinc (unsigned int local_var_index, int ival, int pc)
{
{
  tree local_var, res;
  tree local_var, res;
  tree constant_value;
  tree constant_value;
 
 
  flush_quick_stack ();
  flush_quick_stack ();
  local_var = find_local_variable (local_var_index, int_type_node, pc);
  local_var = find_local_variable (local_var_index, int_type_node, pc);
  constant_value = build_int_cst (NULL_TREE, ival);
  constant_value = build_int_cst (NULL_TREE, ival);
  res = fold_build2 (PLUS_EXPR, int_type_node, local_var, constant_value);
  res = fold_build2 (PLUS_EXPR, int_type_node, local_var, constant_value);
  java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (local_var), local_var, res));
  java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (local_var), local_var, res));
}
}
 
 
 
 
tree
tree
build_java_soft_divmod (enum tree_code op, tree type, tree op1, tree op2)
build_java_soft_divmod (enum tree_code op, tree type, tree op1, tree op2)
{
{
  tree call = NULL;
  tree call = NULL;
  tree arg1 = convert (type, op1);
  tree arg1 = convert (type, op1);
  tree arg2 = convert (type, op2);
  tree arg2 = convert (type, op2);
 
 
  if (type == int_type_node)
  if (type == int_type_node)
    {
    {
      switch (op)
      switch (op)
        {
        {
        case TRUNC_DIV_EXPR:
        case TRUNC_DIV_EXPR:
          call = soft_idiv_node;
          call = soft_idiv_node;
          break;
          break;
        case TRUNC_MOD_EXPR:
        case TRUNC_MOD_EXPR:
          call = soft_irem_node;
          call = soft_irem_node;
          break;
          break;
        default:
        default:
          break;
          break;
        }
        }
    }
    }
  else if (type == long_type_node)
  else if (type == long_type_node)
    {
    {
      switch (op)
      switch (op)
        {
        {
        case TRUNC_DIV_EXPR:
        case TRUNC_DIV_EXPR:
          call = soft_ldiv_node;
          call = soft_ldiv_node;
          break;
          break;
        case TRUNC_MOD_EXPR:
        case TRUNC_MOD_EXPR:
          call = soft_lrem_node;
          call = soft_lrem_node;
          break;
          break;
        default:
        default:
          break;
          break;
        }
        }
    }
    }
 
 
  gcc_assert (call);
  gcc_assert (call);
  call = build_call_nary (type, build_address_of (call), 2, arg1, arg2);
  call = build_call_nary (type, build_address_of (call), 2, arg1, arg2);
  return call;
  return call;
}
}
 
 
tree
tree
build_java_binop (enum tree_code op, tree type, tree arg1, tree arg2)
build_java_binop (enum tree_code op, tree type, tree arg1, tree arg2)
{
{
  tree mask;
  tree mask;
  switch (op)
  switch (op)
    {
    {
    case URSHIFT_EXPR:
    case URSHIFT_EXPR:
      {
      {
        tree u_type = unsigned_type_for (type);
        tree u_type = unsigned_type_for (type);
        arg1 = convert (u_type, arg1);
        arg1 = convert (u_type, arg1);
        arg1 = build_java_binop (RSHIFT_EXPR, u_type, arg1, arg2);
        arg1 = build_java_binop (RSHIFT_EXPR, u_type, arg1, arg2);
        return convert (type, arg1);
        return convert (type, arg1);
      }
      }
    case LSHIFT_EXPR:
    case LSHIFT_EXPR:
    case RSHIFT_EXPR:
    case RSHIFT_EXPR:
      mask = build_int_cst (NULL_TREE,
      mask = build_int_cst (NULL_TREE,
                            TYPE_PRECISION (TREE_TYPE (arg1)) - 1);
                            TYPE_PRECISION (TREE_TYPE (arg1)) - 1);
      arg2 = fold_build2 (BIT_AND_EXPR, int_type_node, arg2, mask);
      arg2 = fold_build2 (BIT_AND_EXPR, int_type_node, arg2, mask);
      break;
      break;
 
 
    case COMPARE_L_EXPR:  /* arg1 > arg2 ?  1 : arg1 == arg2 ? 0 : -1 */
    case COMPARE_L_EXPR:  /* arg1 > arg2 ?  1 : arg1 == arg2 ? 0 : -1 */
    case COMPARE_G_EXPR:  /* arg1 < arg2 ? -1 : arg1 == arg2 ? 0 :  1 */
    case COMPARE_G_EXPR:  /* arg1 < arg2 ? -1 : arg1 == arg2 ? 0 :  1 */
      arg1 = save_expr (arg1);  arg2 = save_expr (arg2);
      arg1 = save_expr (arg1);  arg2 = save_expr (arg2);
      {
      {
        tree ifexp1 = fold_build2 (op == COMPARE_L_EXPR ? GT_EXPR : LT_EXPR,
        tree ifexp1 = fold_build2 (op == COMPARE_L_EXPR ? GT_EXPR : LT_EXPR,
                                   boolean_type_node, arg1, arg2);
                                   boolean_type_node, arg1, arg2);
        tree ifexp2 = fold_build2 (EQ_EXPR, boolean_type_node, arg1, arg2);
        tree ifexp2 = fold_build2 (EQ_EXPR, boolean_type_node, arg1, arg2);
        tree second_compare = fold_build3 (COND_EXPR, int_type_node,
        tree second_compare = fold_build3 (COND_EXPR, int_type_node,
                                           ifexp2, integer_zero_node,
                                           ifexp2, integer_zero_node,
                                           op == COMPARE_L_EXPR
                                           op == COMPARE_L_EXPR
                                           ? integer_minus_one_node
                                           ? integer_minus_one_node
                                           : integer_one_node);
                                           : integer_one_node);
        return fold_build3 (COND_EXPR, int_type_node, ifexp1,
        return fold_build3 (COND_EXPR, int_type_node, ifexp1,
                            op == COMPARE_L_EXPR ? integer_one_node
                            op == COMPARE_L_EXPR ? integer_one_node
                            : integer_minus_one_node,
                            : integer_minus_one_node,
                            second_compare);
                            second_compare);
      }
      }
    case COMPARE_EXPR:
    case COMPARE_EXPR:
      arg1 = save_expr (arg1);  arg2 = save_expr (arg2);
      arg1 = save_expr (arg1);  arg2 = save_expr (arg2);
      {
      {
        tree ifexp1 = fold_build2 (LT_EXPR, boolean_type_node, arg1, arg2);
        tree ifexp1 = fold_build2 (LT_EXPR, boolean_type_node, arg1, arg2);
        tree ifexp2 = fold_build2 (GT_EXPR, boolean_type_node, arg1, arg2);
        tree ifexp2 = fold_build2 (GT_EXPR, boolean_type_node, arg1, arg2);
        tree second_compare = fold_build3 (COND_EXPR, int_type_node,
        tree second_compare = fold_build3 (COND_EXPR, int_type_node,
                                           ifexp2, integer_one_node,
                                           ifexp2, integer_one_node,
                                           integer_zero_node);
                                           integer_zero_node);
        return fold_build3 (COND_EXPR, int_type_node,
        return fold_build3 (COND_EXPR, int_type_node,
                            ifexp1, integer_minus_one_node, second_compare);
                            ifexp1, integer_minus_one_node, second_compare);
      }
      }
    case TRUNC_DIV_EXPR:
    case TRUNC_DIV_EXPR:
    case TRUNC_MOD_EXPR:
    case TRUNC_MOD_EXPR:
      if (TREE_CODE (type) == REAL_TYPE
      if (TREE_CODE (type) == REAL_TYPE
          && op == TRUNC_MOD_EXPR)
          && op == TRUNC_MOD_EXPR)
        {
        {
          tree call;
          tree call;
          if (type != double_type_node)
          if (type != double_type_node)
            {
            {
              arg1 = convert (double_type_node, arg1);
              arg1 = convert (double_type_node, arg1);
              arg2 = convert (double_type_node, arg2);
              arg2 = convert (double_type_node, arg2);
            }
            }
          call = build_call_nary (double_type_node,
          call = build_call_nary (double_type_node,
                                  build_address_of (soft_fmod_node),
                                  build_address_of (soft_fmod_node),
                                  2, arg1, arg2);
                                  2, arg1, arg2);
          if (type != double_type_node)
          if (type != double_type_node)
            call = convert (type, call);
            call = convert (type, call);
          return call;
          return call;
        }
        }
 
 
      if (TREE_CODE (type) == INTEGER_TYPE
      if (TREE_CODE (type) == INTEGER_TYPE
          && flag_use_divide_subroutine
          && flag_use_divide_subroutine
          && ! flag_syntax_only)
          && ! flag_syntax_only)
        return build_java_soft_divmod (op, type, arg1, arg2);
        return build_java_soft_divmod (op, type, arg1, arg2);
 
 
      break;
      break;
    default:  ;
    default:  ;
    }
    }
  return fold_build2 (op, type, arg1, arg2);
  return fold_build2 (op, type, arg1, arg2);
}
}
 
 
static void
static void
expand_java_binop (tree type, enum tree_code op)
expand_java_binop (tree type, enum tree_code op)
{
{
  tree larg, rarg;
  tree larg, rarg;
  tree ltype = type;
  tree ltype = type;
  tree rtype = type;
  tree rtype = type;
  switch (op)
  switch (op)
    {
    {
    case LSHIFT_EXPR:
    case LSHIFT_EXPR:
    case RSHIFT_EXPR:
    case RSHIFT_EXPR:
    case URSHIFT_EXPR:
    case URSHIFT_EXPR:
      rtype = int_type_node;
      rtype = int_type_node;
      rarg = pop_value (rtype);
      rarg = pop_value (rtype);
      break;
      break;
    default:
    default:
      rarg = pop_value (rtype);
      rarg = pop_value (rtype);
    }
    }
  larg = pop_value (ltype);
  larg = pop_value (ltype);
  push_value (build_java_binop (op, type, larg, rarg));
  push_value (build_java_binop (op, type, larg, rarg));
}
}
 
 
/* Lookup the field named NAME in *TYPEP or its super classes.
/* Lookup the field named NAME in *TYPEP or its super classes.
   If not found, return NULL_TREE.
   If not found, return NULL_TREE.
   (If the *TYPEP is not found, or if the field reference is
   (If the *TYPEP is not found, or if the field reference is
   ambiguous, return error_mark_node.)
   ambiguous, return error_mark_node.)
   If found, return the FIELD_DECL, and set *TYPEP to the
   If found, return the FIELD_DECL, and set *TYPEP to the
   class containing the field. */
   class containing the field. */
 
 
tree
tree
lookup_field (tree *typep, tree name)
lookup_field (tree *typep, tree name)
{
{
  if (CLASS_P (*typep) && !CLASS_LOADED_P (*typep))
  if (CLASS_P (*typep) && !CLASS_LOADED_P (*typep))
    {
    {
      load_class (*typep, 1);
      load_class (*typep, 1);
      safe_layout_class (*typep);
      safe_layout_class (*typep);
      if (!TYPE_SIZE (*typep) || TREE_CODE (TYPE_SIZE (*typep)) == ERROR_MARK)
      if (!TYPE_SIZE (*typep) || TREE_CODE (TYPE_SIZE (*typep)) == ERROR_MARK)
        return error_mark_node;
        return error_mark_node;
    }
    }
  do
  do
    {
    {
      tree field, binfo, base_binfo;
      tree field, binfo, base_binfo;
      tree save_field;
      tree save_field;
      int i;
      int i;
 
 
      for (field = TYPE_FIELDS (*typep); field; field = TREE_CHAIN (field))
      for (field = TYPE_FIELDS (*typep); field; field = TREE_CHAIN (field))
        if (DECL_NAME (field) == name)
        if (DECL_NAME (field) == name)
          return field;
          return field;
 
 
      /* Process implemented interfaces. */
      /* Process implemented interfaces. */
      save_field = NULL_TREE;
      save_field = NULL_TREE;
      for (binfo = TYPE_BINFO (*typep), i = 0;
      for (binfo = TYPE_BINFO (*typep), i = 0;
           BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
           BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
        {
        {
          tree t = BINFO_TYPE (base_binfo);
          tree t = BINFO_TYPE (base_binfo);
          if ((field = lookup_field (&t, name)))
          if ((field = lookup_field (&t, name)))
            {
            {
              if (save_field == field)
              if (save_field == field)
                continue;
                continue;
              if (save_field == NULL_TREE)
              if (save_field == NULL_TREE)
                save_field = field;
                save_field = field;
              else
              else
                {
                {
                  tree i1 = DECL_CONTEXT (save_field);
                  tree i1 = DECL_CONTEXT (save_field);
                  tree i2 = DECL_CONTEXT (field);
                  tree i2 = DECL_CONTEXT (field);
                  error ("reference %qs is ambiguous: appears in interface %qs and interface %qs",
                  error ("reference %qs is ambiguous: appears in interface %qs and interface %qs",
                         IDENTIFIER_POINTER (name),
                         IDENTIFIER_POINTER (name),
                         IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (i1))),
                         IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (i1))),
                         IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (i2))));
                         IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (i2))));
                  return error_mark_node;
                  return error_mark_node;
                }
                }
            }
            }
        }
        }
 
 
      if (save_field != NULL_TREE)
      if (save_field != NULL_TREE)
        return save_field;
        return save_field;
 
 
      *typep = CLASSTYPE_SUPER (*typep);
      *typep = CLASSTYPE_SUPER (*typep);
    } while (*typep);
    } while (*typep);
  return NULL_TREE;
  return NULL_TREE;
}
}
 
 
/* Look up the field named NAME in object SELF_VALUE,
/* Look up the field named NAME in object SELF_VALUE,
   which has class SELF_CLASS (a non-handle RECORD_TYPE).
   which has class SELF_CLASS (a non-handle RECORD_TYPE).
   SELF_VALUE is NULL_TREE if looking for a static field. */
   SELF_VALUE is NULL_TREE if looking for a static field. */
 
 
tree
tree
build_field_ref (tree self_value, tree self_class, tree name)
build_field_ref (tree self_value, tree self_class, tree name)
{
{
  tree base_class = self_class;
  tree base_class = self_class;
  tree field_decl = lookup_field (&base_class, name);
  tree field_decl = lookup_field (&base_class, name);
  if (field_decl == NULL_TREE)
  if (field_decl == NULL_TREE)
    {
    {
      error ("field %qs not found", IDENTIFIER_POINTER (name));
      error ("field %qs not found", IDENTIFIER_POINTER (name));
      return error_mark_node;
      return error_mark_node;
    }
    }
  if (self_value == NULL_TREE)
  if (self_value == NULL_TREE)
    {
    {
      return build_static_field_ref (field_decl);
      return build_static_field_ref (field_decl);
    }
    }
  else
  else
    {
    {
      tree base_type = promote_type (base_class);
      tree base_type = promote_type (base_class);
 
 
      /* CHECK is true if self_value is not the this pointer.  */
      /* CHECK is true if self_value is not the this pointer.  */
      int check = (! (DECL_P (self_value)
      int check = (! (DECL_P (self_value)
                      && DECL_NAME (self_value) == this_identifier_node));
                      && DECL_NAME (self_value) == this_identifier_node));
 
 
      /* Determine whether a field offset from NULL will lie within
      /* Determine whether a field offset from NULL will lie within
         Page 0: this is necessary on those GNU/Linux/BSD systems that
         Page 0: this is necessary on those GNU/Linux/BSD systems that
         trap SEGV to generate NullPointerExceptions.
         trap SEGV to generate NullPointerExceptions.
 
 
         We assume that Page 0 will be mapped with NOPERM, and that
         We assume that Page 0 will be mapped with NOPERM, and that
         memory may be allocated from any other page, so only field
         memory may be allocated from any other page, so only field
         offsets < pagesize are guaranteed to trap.  We also assume
         offsets < pagesize are guaranteed to trap.  We also assume
         the smallest page size we'll encounter is 4k bytes.  */
         the smallest page size we'll encounter is 4k bytes.  */
      if (! flag_syntax_only && check && ! flag_check_references
      if (! flag_syntax_only && check && ! flag_check_references
          && ! flag_indirect_dispatch)
          && ! flag_indirect_dispatch)
        {
        {
          tree field_offset = byte_position (field_decl);
          tree field_offset = byte_position (field_decl);
          if (! page_size)
          if (! page_size)
            page_size = size_int (4096);
            page_size = size_int (4096);
          check = ! INT_CST_LT_UNSIGNED (field_offset, page_size);
          check = ! INT_CST_LT_UNSIGNED (field_offset, page_size);
        }
        }
 
 
      if (base_type != TREE_TYPE (self_value))
      if (base_type != TREE_TYPE (self_value))
        self_value = fold_build1 (NOP_EXPR, base_type, self_value);
        self_value = fold_build1 (NOP_EXPR, base_type, self_value);
      if (! flag_syntax_only && flag_indirect_dispatch)
      if (! flag_syntax_only && flag_indirect_dispatch)
        {
        {
          tree otable_index
          tree otable_index
            = build_int_cst (NULL_TREE, get_symbol_table_index
            = build_int_cst (NULL_TREE, get_symbol_table_index
                             (field_decl, NULL_TREE,
                             (field_decl, NULL_TREE,
                              &TYPE_OTABLE_METHODS (output_class)));
                              &TYPE_OTABLE_METHODS (output_class)));
          tree field_offset
          tree field_offset
            = build4 (ARRAY_REF, integer_type_node,
            = build4 (ARRAY_REF, integer_type_node,
                      TYPE_OTABLE_DECL (output_class), otable_index,
                      TYPE_OTABLE_DECL (output_class), otable_index,
                      NULL_TREE, NULL_TREE);
                      NULL_TREE, NULL_TREE);
          tree address;
          tree address;
 
 
          if (DECL_CONTEXT (field_decl) != output_class)
          if (DECL_CONTEXT (field_decl) != output_class)
            field_offset
            field_offset
              = build3 (COND_EXPR, TREE_TYPE (field_offset),
              = build3 (COND_EXPR, TREE_TYPE (field_offset),
                        build2 (EQ_EXPR, boolean_type_node,
                        build2 (EQ_EXPR, boolean_type_node,
                                field_offset, integer_zero_node),
                                field_offset, integer_zero_node),
                        build_call_nary (void_type_node,
                        build_call_nary (void_type_node,
                                         build_address_of (soft_nosuchfield_node),
                                         build_address_of (soft_nosuchfield_node),
                                         1, otable_index),
                                         1, otable_index),
                        field_offset);
                        field_offset);
 
 
          field_offset = fold (convert (sizetype, field_offset));
          field_offset = fold (convert (sizetype, field_offset));
          self_value = java_check_reference (self_value, check);
          self_value = java_check_reference (self_value, check);
          address
          address
            = fold_build2 (POINTER_PLUS_EXPR,
            = fold_build2 (POINTER_PLUS_EXPR,
                           TREE_TYPE (self_value),
                           TREE_TYPE (self_value),
                           self_value, field_offset);
                           self_value, field_offset);
          address = fold_convert (build_pointer_type (TREE_TYPE (field_decl)),
          address = fold_convert (build_pointer_type (TREE_TYPE (field_decl)),
                                  address);
                                  address);
          return fold_build1 (INDIRECT_REF, TREE_TYPE (field_decl), address);
          return fold_build1 (INDIRECT_REF, TREE_TYPE (field_decl), address);
        }
        }
 
 
      self_value = build_java_indirect_ref (TREE_TYPE (TREE_TYPE (self_value)),
      self_value = build_java_indirect_ref (TREE_TYPE (TREE_TYPE (self_value)),
                                            self_value, check);
                                            self_value, check);
      return fold_build3 (COMPONENT_REF, TREE_TYPE (field_decl),
      return fold_build3 (COMPONENT_REF, TREE_TYPE (field_decl),
                          self_value, field_decl, NULL_TREE);
                          self_value, field_decl, NULL_TREE);
    }
    }
}
}
 
 
tree
tree
lookup_label (int pc)
lookup_label (int pc)
{
{
  tree name;
  tree name;
  char buf[32];
  char buf[32];
  if (pc > highest_label_pc_this_method)
  if (pc > highest_label_pc_this_method)
    highest_label_pc_this_method = pc;
    highest_label_pc_this_method = pc;
  ASM_GENERATE_INTERNAL_LABEL(buf, "LJpc=", start_label_pc_this_method + pc);
  ASM_GENERATE_INTERNAL_LABEL(buf, "LJpc=", start_label_pc_this_method + pc);
  name = get_identifier (buf);
  name = get_identifier (buf);
  if (IDENTIFIER_LOCAL_VALUE (name))
  if (IDENTIFIER_LOCAL_VALUE (name))
    return IDENTIFIER_LOCAL_VALUE (name);
    return IDENTIFIER_LOCAL_VALUE (name);
  else
  else
    {
    {
      /* The type of the address of a label is return_address_type_node. */
      /* The type of the address of a label is return_address_type_node. */
      tree decl = create_label_decl (name);
      tree decl = create_label_decl (name);
      return pushdecl (decl);
      return pushdecl (decl);
    }
    }
}
}
 
 
/* Generate a unique name for the purpose of loops and switches
/* Generate a unique name for the purpose of loops and switches
   labels, and try-catch-finally blocks label or temporary variables.  */
   labels, and try-catch-finally blocks label or temporary variables.  */
 
 
tree
tree
generate_name (void)
generate_name (void)
{
{
  static int l_number = 0;
  static int l_number = 0;
  char buff [32];
  char buff [32];
  ASM_GENERATE_INTERNAL_LABEL(buff, "LJv", l_number);
  ASM_GENERATE_INTERNAL_LABEL(buff, "LJv", l_number);
  l_number++;
  l_number++;
  return get_identifier (buff);
  return get_identifier (buff);
}
}
 
 
tree
tree
create_label_decl (tree name)
create_label_decl (tree name)
{
{
  tree decl;
  tree decl;
  decl = build_decl (input_location, LABEL_DECL, name,
  decl = build_decl (input_location, LABEL_DECL, name,
                     TREE_TYPE (return_address_type_node));
                     TREE_TYPE (return_address_type_node));
  DECL_CONTEXT (decl) = current_function_decl;
  DECL_CONTEXT (decl) = current_function_decl;
  DECL_IGNORED_P (decl) = 1;
  DECL_IGNORED_P (decl) = 1;
  return decl;
  return decl;
}
}
 
 
/* This maps a bytecode offset (PC) to various flags.  */
/* This maps a bytecode offset (PC) to various flags.  */
char *instruction_bits;
char *instruction_bits;
 
 
/* This is a vector of type states for the current method.  It is
/* This is a vector of type states for the current method.  It is
   indexed by PC.  Each element is a tree vector holding the type
   indexed by PC.  Each element is a tree vector holding the type
   state at that PC.  We only note type states at basic block
   state at that PC.  We only note type states at basic block
   boundaries.  */
   boundaries.  */
VEC(tree, gc) *type_states;
VEC(tree, gc) *type_states;
 
 
static void
static void
note_label (int current_pc ATTRIBUTE_UNUSED, int target_pc)
note_label (int current_pc ATTRIBUTE_UNUSED, int target_pc)
{
{
  lookup_label (target_pc);
  lookup_label (target_pc);
  instruction_bits [target_pc] |= BCODE_JUMP_TARGET;
  instruction_bits [target_pc] |= BCODE_JUMP_TARGET;
}
}
 
 
/* Emit code to jump to TARGET_PC if VALUE1 CONDITION VALUE2,
/* Emit code to jump to TARGET_PC if VALUE1 CONDITION VALUE2,
   where CONDITION is one of one the compare operators. */
   where CONDITION is one of one the compare operators. */
 
 
static void
static void
expand_compare (enum tree_code condition, tree value1, tree value2,
expand_compare (enum tree_code condition, tree value1, tree value2,
                int target_pc)
                int target_pc)
{
{
  tree target = lookup_label (target_pc);
  tree target = lookup_label (target_pc);
  tree cond = fold_build2 (condition, boolean_type_node, value1, value2);
  tree cond = fold_build2 (condition, boolean_type_node, value1, value2);
  java_add_stmt
  java_add_stmt
    (build3 (COND_EXPR, void_type_node, java_truthvalue_conversion (cond),
    (build3 (COND_EXPR, void_type_node, java_truthvalue_conversion (cond),
             build1 (GOTO_EXPR, void_type_node, target),
             build1 (GOTO_EXPR, void_type_node, target),
             build_java_empty_stmt ()));
             build_java_empty_stmt ()));
}
}
 
 
/* Emit code for a TEST-type opcode. */
/* Emit code for a TEST-type opcode. */
 
 
static void
static void
expand_test (enum tree_code condition, tree type, int target_pc)
expand_test (enum tree_code condition, tree type, int target_pc)
{
{
  tree value1, value2;
  tree value1, value2;
  flush_quick_stack ();
  flush_quick_stack ();
  value1 = pop_value (type);
  value1 = pop_value (type);
  value2 = (type == ptr_type_node) ? null_pointer_node : integer_zero_node;
  value2 = (type == ptr_type_node) ? null_pointer_node : integer_zero_node;
  expand_compare (condition, value1, value2, target_pc);
  expand_compare (condition, value1, value2, target_pc);
}
}
 
 
/* Emit code for a COND-type opcode. */
/* Emit code for a COND-type opcode. */
 
 
static void
static void
expand_cond (enum tree_code condition, tree type, int target_pc)
expand_cond (enum tree_code condition, tree type, int target_pc)
{
{
  tree value1, value2;
  tree value1, value2;
  flush_quick_stack ();
  flush_quick_stack ();
  /* note: pop values in opposite order */
  /* note: pop values in opposite order */
  value2 = pop_value (type);
  value2 = pop_value (type);
  value1 = pop_value (type);
  value1 = pop_value (type);
  /* Maybe should check value1 and value2 for type compatibility ??? */
  /* Maybe should check value1 and value2 for type compatibility ??? */
  expand_compare (condition, value1, value2, target_pc);
  expand_compare (condition, value1, value2, target_pc);
}
}
 
 
static void
static void
expand_java_goto (int target_pc)
expand_java_goto (int target_pc)
{
{
  tree target_label = lookup_label (target_pc);
  tree target_label = lookup_label (target_pc);
  flush_quick_stack ();
  flush_quick_stack ();
  java_add_stmt (build1 (GOTO_EXPR, void_type_node, target_label));
  java_add_stmt (build1 (GOTO_EXPR, void_type_node, target_label));
}
}
 
 
static tree
static tree
expand_java_switch (tree selector, int default_pc)
expand_java_switch (tree selector, int default_pc)
{
{
  tree switch_expr, x;
  tree switch_expr, x;
 
 
  flush_quick_stack ();
  flush_quick_stack ();
  switch_expr = build3 (SWITCH_EXPR, TREE_TYPE (selector), selector,
  switch_expr = build3 (SWITCH_EXPR, TREE_TYPE (selector), selector,
                        NULL_TREE, NULL_TREE);
                        NULL_TREE, NULL_TREE);
  java_add_stmt (switch_expr);
  java_add_stmt (switch_expr);
 
 
  x = build3 (CASE_LABEL_EXPR, void_type_node, NULL_TREE, NULL_TREE,
  x = build3 (CASE_LABEL_EXPR, void_type_node, NULL_TREE, NULL_TREE,
              create_artificial_label (input_location));
              create_artificial_label (input_location));
  append_to_statement_list (x, &SWITCH_BODY (switch_expr));
  append_to_statement_list (x, &SWITCH_BODY (switch_expr));
 
 
  x = build1 (GOTO_EXPR, void_type_node, lookup_label (default_pc));
  x = build1 (GOTO_EXPR, void_type_node, lookup_label (default_pc));
  append_to_statement_list (x, &SWITCH_BODY (switch_expr));
  append_to_statement_list (x, &SWITCH_BODY (switch_expr));
 
 
  return switch_expr;
  return switch_expr;
}
}
 
 
static void
static void
expand_java_add_case (tree switch_expr, int match, int target_pc)
expand_java_add_case (tree switch_expr, int match, int target_pc)
{
{
  tree value, x;
  tree value, x;
 
 
  value = build_int_cst (TREE_TYPE (switch_expr), match);
  value = build_int_cst (TREE_TYPE (switch_expr), match);
 
 
  x = build3 (CASE_LABEL_EXPR, void_type_node, value, NULL_TREE,
  x = build3 (CASE_LABEL_EXPR, void_type_node, value, NULL_TREE,
              create_artificial_label (input_location));
              create_artificial_label (input_location));
  append_to_statement_list (x, &SWITCH_BODY (switch_expr));
  append_to_statement_list (x, &SWITCH_BODY (switch_expr));
 
 
  x = build1 (GOTO_EXPR, void_type_node, lookup_label (target_pc));
  x = build1 (GOTO_EXPR, void_type_node, lookup_label (target_pc));
  append_to_statement_list (x, &SWITCH_BODY (switch_expr));
  append_to_statement_list (x, &SWITCH_BODY (switch_expr));
}
}
 
 
static tree
static tree
pop_arguments (tree arg_types)
pop_arguments (tree arg_types)
{
{
  if (arg_types == end_params_node)
  if (arg_types == end_params_node)
    return NULL_TREE;
    return NULL_TREE;
  if (TREE_CODE (arg_types) == TREE_LIST)
  if (TREE_CODE (arg_types) == TREE_LIST)
    {
    {
      tree tail = pop_arguments (TREE_CHAIN (arg_types));
      tree tail = pop_arguments (TREE_CHAIN (arg_types));
      tree type = TREE_VALUE (arg_types);
      tree type = TREE_VALUE (arg_types);
      tree arg = pop_value (type);
      tree arg = pop_value (type);
 
 
      /* We simply cast each argument to its proper type.  This is
      /* We simply cast each argument to its proper type.  This is
         needed since we lose type information coming out of the
         needed since we lose type information coming out of the
         verifier.  We also have to do this when we pop an integer
         verifier.  We also have to do this when we pop an integer
         type that must be promoted for the function call.  */
         type that must be promoted for the function call.  */
      if (TREE_CODE (type) == POINTER_TYPE)
      if (TREE_CODE (type) == POINTER_TYPE)
        arg = build1 (NOP_EXPR, type, arg);
        arg = build1 (NOP_EXPR, type, arg);
      else if (targetm.calls.promote_prototypes (type)
      else if (targetm.calls.promote_prototypes (type)
               && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)
               && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)
               && INTEGRAL_TYPE_P (type))
               && INTEGRAL_TYPE_P (type))
        arg = convert (integer_type_node, arg);
        arg = convert (integer_type_node, arg);
      return tree_cons (NULL_TREE, arg, tail);
      return tree_cons (NULL_TREE, arg, tail);
    }
    }
  gcc_unreachable ();
  gcc_unreachable ();
}
}
 
 
/* Attach to PTR (a block) the declaration found in ENTRY. */
/* Attach to PTR (a block) the declaration found in ENTRY. */
 
 
int
int
attach_init_test_initialization_flags (void **entry, void *ptr)
attach_init_test_initialization_flags (void **entry, void *ptr)
{
{
  tree block = (tree)ptr;
  tree block = (tree)ptr;
  struct treetreehash_entry *ite = (struct treetreehash_entry *) *entry;
  struct treetreehash_entry *ite = (struct treetreehash_entry *) *entry;
 
 
  if (block != error_mark_node)
  if (block != error_mark_node)
    {
    {
      if (TREE_CODE (block) == BIND_EXPR)
      if (TREE_CODE (block) == BIND_EXPR)
        {
        {
          tree body = BIND_EXPR_BODY (block);
          tree body = BIND_EXPR_BODY (block);
          TREE_CHAIN (ite->value) = BIND_EXPR_VARS (block);
          TREE_CHAIN (ite->value) = BIND_EXPR_VARS (block);
          BIND_EXPR_VARS (block) = ite->value;
          BIND_EXPR_VARS (block) = ite->value;
          body = build2 (COMPOUND_EXPR, void_type_node,
          body = build2 (COMPOUND_EXPR, void_type_node,
                         build1 (DECL_EXPR, void_type_node, ite->value), body);
                         build1 (DECL_EXPR, void_type_node, ite->value), body);
          BIND_EXPR_BODY (block) = body;
          BIND_EXPR_BODY (block) = body;
        }
        }
      else
      else
        {
        {
          tree body = BLOCK_SUBBLOCKS (block);
          tree body = BLOCK_SUBBLOCKS (block);
          TREE_CHAIN (ite->value) = BLOCK_EXPR_DECLS (block);
          TREE_CHAIN (ite->value) = BLOCK_EXPR_DECLS (block);
          BLOCK_EXPR_DECLS (block) = ite->value;
          BLOCK_EXPR_DECLS (block) = ite->value;
          body = build2 (COMPOUND_EXPR, void_type_node,
          body = build2 (COMPOUND_EXPR, void_type_node,
                         build1 (DECL_EXPR, void_type_node, ite->value), body);
                         build1 (DECL_EXPR, void_type_node, ite->value), body);
          BLOCK_SUBBLOCKS (block) = body;
          BLOCK_SUBBLOCKS (block) = body;
        }
        }
 
 
    }
    }
  return true;
  return true;
}
}
 
 
/* Build an expression to initialize the class CLAS.
/* Build an expression to initialize the class CLAS.
   if EXPR is non-NULL, returns an expression to first call the initializer
   if EXPR is non-NULL, returns an expression to first call the initializer
   (if it is needed) and then calls EXPR. */
   (if it is needed) and then calls EXPR. */
 
 
tree
tree
build_class_init (tree clas, tree expr)
build_class_init (tree clas, tree expr)
{
{
  tree init;
  tree init;
 
 
  /* An optimization: if CLAS is a superclass of the class we're
  /* An optimization: if CLAS is a superclass of the class we're
     compiling, we don't need to initialize it.  However, if CLAS is
     compiling, we don't need to initialize it.  However, if CLAS is
     an interface, it won't necessarily be initialized, even if we
     an interface, it won't necessarily be initialized, even if we
     implement it.  */
     implement it.  */
  if ((! CLASS_INTERFACE (TYPE_NAME (clas))
  if ((! CLASS_INTERFACE (TYPE_NAME (clas))
       && inherits_from_p (current_class, clas))
       && inherits_from_p (current_class, clas))
      || current_class == clas)
      || current_class == clas)
    return expr;
    return expr;
 
 
  if (always_initialize_class_p)
  if (always_initialize_class_p)
    {
    {
      init = build_call_nary (void_type_node,
      init = build_call_nary (void_type_node,
                              build_address_of (soft_initclass_node),
                              build_address_of (soft_initclass_node),
                              1, build_class_ref (clas));
                              1, build_class_ref (clas));
      TREE_SIDE_EFFECTS (init) = 1;
      TREE_SIDE_EFFECTS (init) = 1;
    }
    }
  else
  else
    {
    {
      tree *init_test_decl;
      tree *init_test_decl;
      tree decl;
      tree decl;
      init_test_decl = java_treetreehash_new
      init_test_decl = java_treetreehash_new
        (DECL_FUNCTION_INIT_TEST_TABLE (current_function_decl), clas);
        (DECL_FUNCTION_INIT_TEST_TABLE (current_function_decl), clas);
 
 
      if (*init_test_decl == NULL)
      if (*init_test_decl == NULL)
        {
        {
          /* Build a declaration and mark it as a flag used to track
          /* Build a declaration and mark it as a flag used to track
             static class initializations. */
             static class initializations. */
          decl = build_decl (input_location, VAR_DECL, NULL_TREE,
          decl = build_decl (input_location, VAR_DECL, NULL_TREE,
                             boolean_type_node);
                             boolean_type_node);
          MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
          MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
          DECL_CONTEXT (decl) = current_function_decl;
          DECL_CONTEXT (decl) = current_function_decl;
          DECL_INITIAL (decl) = boolean_false_node;
          DECL_INITIAL (decl) = boolean_false_node;
          /* Don't emit any symbolic debugging info for this decl.  */
          /* Don't emit any symbolic debugging info for this decl.  */
          DECL_IGNORED_P (decl) = 1;
          DECL_IGNORED_P (decl) = 1;
          *init_test_decl = decl;
          *init_test_decl = decl;
        }
        }
 
 
      init = build_call_nary (void_type_node,
      init = build_call_nary (void_type_node,
                              build_address_of (soft_initclass_node),
                              build_address_of (soft_initclass_node),
                              1, build_class_ref (clas));
                              1, build_class_ref (clas));
      TREE_SIDE_EFFECTS (init) = 1;
      TREE_SIDE_EFFECTS (init) = 1;
      init = build3 (COND_EXPR, void_type_node,
      init = build3 (COND_EXPR, void_type_node,
                     build2 (EQ_EXPR, boolean_type_node,
                     build2 (EQ_EXPR, boolean_type_node,
                             *init_test_decl, boolean_false_node),
                             *init_test_decl, boolean_false_node),
                     init, integer_zero_node);
                     init, integer_zero_node);
      TREE_SIDE_EFFECTS (init) = 1;
      TREE_SIDE_EFFECTS (init) = 1;
      init = build2 (COMPOUND_EXPR, TREE_TYPE (expr), init,
      init = build2 (COMPOUND_EXPR, TREE_TYPE (expr), init,
                     build2 (MODIFY_EXPR, boolean_type_node,
                     build2 (MODIFY_EXPR, boolean_type_node,
                             *init_test_decl, boolean_true_node));
                             *init_test_decl, boolean_true_node));
      TREE_SIDE_EFFECTS (init) = 1;
      TREE_SIDE_EFFECTS (init) = 1;
    }
    }
 
 
  if (expr != NULL_TREE)
  if (expr != NULL_TREE)
    {
    {
      expr = build2 (COMPOUND_EXPR, TREE_TYPE (expr), init, expr);
      expr = build2 (COMPOUND_EXPR, TREE_TYPE (expr), init, expr);
      TREE_SIDE_EFFECTS (expr) = 1;
      TREE_SIDE_EFFECTS (expr) = 1;
      return expr;
      return expr;
    }
    }
  return init;
  return init;
}
}
 
 


 
 
/* Rewrite expensive calls that require stack unwinding at runtime to
/* Rewrite expensive calls that require stack unwinding at runtime to
   cheaper alternatives.  The logic here performs these
   cheaper alternatives.  The logic here performs these
   transformations:
   transformations:
 
 
   java.lang.Class.forName("foo") -> java.lang.Class.forName("foo", class$)
   java.lang.Class.forName("foo") -> java.lang.Class.forName("foo", class$)
   java.lang.Class.getClassLoader() -> java.lang.Class.getClassLoader(class$)
   java.lang.Class.getClassLoader() -> java.lang.Class.getClassLoader(class$)
 
 
*/
*/
 
 
typedef struct
typedef struct
{
{
  const char *classname;
  const char *classname;
  const char *method;
  const char *method;
  const char *signature;
  const char *signature;
  const char *new_classname;
  const char *new_classname;
  const char *new_signature;
  const char *new_signature;
  int flags;
  int flags;
  tree (*rewrite_arglist) (tree arglist);
  tree (*rewrite_arglist) (tree arglist);
} rewrite_rule;
} rewrite_rule;
 
 
/* Add __builtin_return_address(0) to the end of an arglist.  */
/* Add __builtin_return_address(0) to the end of an arglist.  */
 
 
 
 
static tree
static tree
rewrite_arglist_getcaller (tree arglist)
rewrite_arglist_getcaller (tree arglist)
{
{
  tree retaddr
  tree retaddr
    = build_call_expr (built_in_decls[BUILT_IN_RETURN_ADDRESS],
    = build_call_expr (built_in_decls[BUILT_IN_RETURN_ADDRESS],
                       1, integer_zero_node);
                       1, integer_zero_node);
 
 
  DECL_UNINLINABLE (current_function_decl) = 1;
  DECL_UNINLINABLE (current_function_decl) = 1;
 
 
  return chainon (arglist,
  return chainon (arglist,
                  tree_cons (NULL_TREE, retaddr,
                  tree_cons (NULL_TREE, retaddr,
                             NULL_TREE));
                             NULL_TREE));
}
}
 
 
/* Add this.class to the end of an arglist.  */
/* Add this.class to the end of an arglist.  */
 
 
static tree
static tree
rewrite_arglist_getclass (tree arglist)
rewrite_arglist_getclass (tree arglist)
{
{
  return chainon (arglist,
  return chainon (arglist,
                  tree_cons (NULL_TREE, build_class_ref (output_class),
                  tree_cons (NULL_TREE, build_class_ref (output_class),
                             NULL_TREE));
                             NULL_TREE));
}
}
 
 
static rewrite_rule rules[] =
static rewrite_rule rules[] =
  {{"java.lang.Class", "getClassLoader", "()Ljava/lang/ClassLoader;",
  {{"java.lang.Class", "getClassLoader", "()Ljava/lang/ClassLoader;",
    "java.lang.Class", "(Ljava/lang/Class;)Ljava/lang/ClassLoader;",
    "java.lang.Class", "(Ljava/lang/Class;)Ljava/lang/ClassLoader;",
    ACC_FINAL|ACC_PRIVATE, rewrite_arglist_getclass},
    ACC_FINAL|ACC_PRIVATE, rewrite_arglist_getclass},
 
 
   {"java.lang.Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;",
   {"java.lang.Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;",
    "java.lang.Class", "(Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Class;",
    "java.lang.Class", "(Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Class;",
    ACC_FINAL|ACC_PRIVATE|ACC_STATIC, rewrite_arglist_getclass},
    ACC_FINAL|ACC_PRIVATE|ACC_STATIC, rewrite_arglist_getclass},
 
 
   {"gnu.classpath.VMStackWalker", "getCallingClass", "()Ljava/lang/Class;",
   {"gnu.classpath.VMStackWalker", "getCallingClass", "()Ljava/lang/Class;",
    "gnu.classpath.VMStackWalker", "(Lgnu/gcj/RawData;)Ljava/lang/Class;",
    "gnu.classpath.VMStackWalker", "(Lgnu/gcj/RawData;)Ljava/lang/Class;",
    ACC_FINAL|ACC_PRIVATE|ACC_STATIC, rewrite_arglist_getcaller},
    ACC_FINAL|ACC_PRIVATE|ACC_STATIC, rewrite_arglist_getcaller},
 
 
   {"gnu.classpath.VMStackWalker", "getCallingClassLoader",
   {"gnu.classpath.VMStackWalker", "getCallingClassLoader",
    "()Ljava/lang/ClassLoader;",
    "()Ljava/lang/ClassLoader;",
    "gnu.classpath.VMStackWalker", "(Lgnu/gcj/RawData;)Ljava/lang/ClassLoader;",
    "gnu.classpath.VMStackWalker", "(Lgnu/gcj/RawData;)Ljava/lang/ClassLoader;",
    ACC_FINAL|ACC_PRIVATE|ACC_STATIC, rewrite_arglist_getcaller},
    ACC_FINAL|ACC_PRIVATE|ACC_STATIC, rewrite_arglist_getcaller},
 
 
   {"gnu.java.lang.VMCPStringBuilder", "toString", "([CII)Ljava/lang/String;",
   {"gnu.java.lang.VMCPStringBuilder", "toString", "([CII)Ljava/lang/String;",
    "java.lang.String", "([CII)Ljava/lang/String;",
    "java.lang.String", "([CII)Ljava/lang/String;",
    ACC_FINAL|ACC_PRIVATE|ACC_STATIC, NULL},
    ACC_FINAL|ACC_PRIVATE|ACC_STATIC, NULL},
 
 
   {NULL, NULL, NULL, NULL, NULL, 0, NULL}};
   {NULL, NULL, NULL, NULL, NULL, 0, NULL}};
 
 
/* True if this method is special, i.e. it's a private method that
/* True if this method is special, i.e. it's a private method that
   should be exported from a DSO.  */
   should be exported from a DSO.  */
 
 
bool
bool
special_method_p (tree candidate_method)
special_method_p (tree candidate_method)
{
{
  tree context = DECL_NAME (TYPE_NAME (DECL_CONTEXT (candidate_method)));
  tree context = DECL_NAME (TYPE_NAME (DECL_CONTEXT (candidate_method)));
  tree method = DECL_NAME (candidate_method);
  tree method = DECL_NAME (candidate_method);
  rewrite_rule *p;
  rewrite_rule *p;
 
 
  for (p = rules; p->classname; p++)
  for (p = rules; p->classname; p++)
    {
    {
      if (get_identifier (p->classname) == context
      if (get_identifier (p->classname) == context
          && get_identifier (p->method) == method)
          && get_identifier (p->method) == method)
        return true;
        return true;
    }
    }
  return false;
  return false;
}
}
 
 
/* Scan the rules list for replacements for *METHOD_P and replace the
/* Scan the rules list for replacements for *METHOD_P and replace the
   args accordingly.  If the rewrite results in an access to a private
   args accordingly.  If the rewrite results in an access to a private
   method, update SPECIAL.*/
   method, update SPECIAL.*/
 
 
void
void
maybe_rewrite_invocation (tree *method_p, tree *arg_list_p,
maybe_rewrite_invocation (tree *method_p, tree *arg_list_p,
                          tree *method_signature_p, tree *special)
                          tree *method_signature_p, tree *special)
{
{
  tree context = DECL_NAME (TYPE_NAME (DECL_CONTEXT (*method_p)));
  tree context = DECL_NAME (TYPE_NAME (DECL_CONTEXT (*method_p)));
  rewrite_rule *p;
  rewrite_rule *p;
  *special = NULL_TREE;
  *special = NULL_TREE;
 
 
  for (p = rules; p->classname; p++)
  for (p = rules; p->classname; p++)
    {
    {
      if (get_identifier (p->classname) == context)
      if (get_identifier (p->classname) == context)
        {
        {
          tree method = DECL_NAME (*method_p);
          tree method = DECL_NAME (*method_p);
          if (get_identifier (p->method) == method
          if (get_identifier (p->method) == method
              && get_identifier (p->signature) == *method_signature_p)
              && get_identifier (p->signature) == *method_signature_p)
            {
            {
              tree maybe_method;
              tree maybe_method;
              tree destination_class
              tree destination_class
                = lookup_class (get_identifier (p->new_classname));
                = lookup_class (get_identifier (p->new_classname));
              gcc_assert (destination_class);
              gcc_assert (destination_class);
              maybe_method
              maybe_method
                = lookup_java_method (destination_class,
                = lookup_java_method (destination_class,
                                      method,
                                      method,
                                      get_identifier (p->new_signature));
                                      get_identifier (p->new_signature));
              if (! maybe_method && ! flag_verify_invocations)
              if (! maybe_method && ! flag_verify_invocations)
                {
                {
                  maybe_method
                  maybe_method
                    = add_method (destination_class, p->flags,
                    = add_method (destination_class, p->flags,
                                  method, get_identifier (p->new_signature));
                                  method, get_identifier (p->new_signature));
                  DECL_EXTERNAL (maybe_method) = 1;
                  DECL_EXTERNAL (maybe_method) = 1;
                }
                }
              *method_p = maybe_method;
              *method_p = maybe_method;
              gcc_assert (*method_p);
              gcc_assert (*method_p);
              if (p->rewrite_arglist)
              if (p->rewrite_arglist)
                *arg_list_p = p->rewrite_arglist (*arg_list_p);
                *arg_list_p = p->rewrite_arglist (*arg_list_p);
              *method_signature_p = get_identifier (p->new_signature);
              *method_signature_p = get_identifier (p->new_signature);
              *special = integer_one_node;
              *special = integer_one_node;
 
 
              break;
              break;
            }
            }
        }
        }
    }
    }
}
}
 
 


 
 
tree
tree
build_known_method_ref (tree method, tree method_type ATTRIBUTE_UNUSED,
build_known_method_ref (tree method, tree method_type ATTRIBUTE_UNUSED,
                        tree self_type, tree method_signature ATTRIBUTE_UNUSED,
                        tree self_type, tree method_signature ATTRIBUTE_UNUSED,
                        tree arg_list ATTRIBUTE_UNUSED, tree special)
                        tree arg_list ATTRIBUTE_UNUSED, tree special)
{
{
  tree func;
  tree func;
  if (is_compiled_class (self_type))
  if (is_compiled_class (self_type))
    {
    {
      /* With indirect dispatch we have to use indirect calls for all
      /* With indirect dispatch we have to use indirect calls for all
         publicly visible methods or gcc will use PLT indirections
         publicly visible methods or gcc will use PLT indirections
         to reach them.  We also have to use indirect dispatch for all
         to reach them.  We also have to use indirect dispatch for all
         external methods.  */
         external methods.  */
      if (! flag_indirect_dispatch
      if (! flag_indirect_dispatch
          || (! DECL_EXTERNAL (method) && ! TREE_PUBLIC (method)))
          || (! DECL_EXTERNAL (method) && ! TREE_PUBLIC (method)))
        {
        {
          func = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (method)),
          func = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (method)),
                         method);
                         method);
        }
        }
      else
      else
        {
        {
          tree table_index
          tree table_index
            = build_int_cst (NULL_TREE,
            = build_int_cst (NULL_TREE,
                             (get_symbol_table_index
                             (get_symbol_table_index
                              (method, special,
                              (method, special,
                               &TYPE_ATABLE_METHODS (output_class))));
                               &TYPE_ATABLE_METHODS (output_class))));
          func
          func
            = build4 (ARRAY_REF,
            = build4 (ARRAY_REF,
                      TREE_TYPE (TREE_TYPE (TYPE_ATABLE_DECL (output_class))),
                      TREE_TYPE (TREE_TYPE (TYPE_ATABLE_DECL (output_class))),
                      TYPE_ATABLE_DECL (output_class), table_index,
                      TYPE_ATABLE_DECL (output_class), table_index,
                      NULL_TREE, NULL_TREE);
                      NULL_TREE, NULL_TREE);
        }
        }
      func = convert (method_ptr_type_node, func);
      func = convert (method_ptr_type_node, func);
    }
    }
  else
  else
    {
    {
      /* We don't know whether the method has been (statically) compiled.
      /* We don't know whether the method has been (statically) compiled.
         Compile this code to get a reference to the method's code:
         Compile this code to get a reference to the method's code:
 
 
         SELF_TYPE->methods[METHOD_INDEX].ncode
         SELF_TYPE->methods[METHOD_INDEX].ncode
 
 
      */
      */
 
 
      int method_index = 0;
      int method_index = 0;
      tree meth, ref;
      tree meth, ref;
 
 
      /* The method might actually be declared in some superclass, so
      /* The method might actually be declared in some superclass, so
         we have to use its class context, not the caller's notion of
         we have to use its class context, not the caller's notion of
         where the method is.  */
         where the method is.  */
      self_type = DECL_CONTEXT (method);
      self_type = DECL_CONTEXT (method);
      ref = build_class_ref (self_type);
      ref = build_class_ref (self_type);
      ref = build1 (INDIRECT_REF, class_type_node, ref);
      ref = build1 (INDIRECT_REF, class_type_node, ref);
      if (ncode_ident == NULL_TREE)
      if (ncode_ident == NULL_TREE)
        ncode_ident = get_identifier ("ncode");
        ncode_ident = get_identifier ("ncode");
      if (methods_ident == NULL_TREE)
      if (methods_ident == NULL_TREE)
        methods_ident = get_identifier ("methods");
        methods_ident = get_identifier ("methods");
      ref = build3 (COMPONENT_REF, method_ptr_type_node, ref,
      ref = build3 (COMPONENT_REF, method_ptr_type_node, ref,
                    lookup_field (&class_type_node, methods_ident),
                    lookup_field (&class_type_node, methods_ident),
                    NULL_TREE);
                    NULL_TREE);
      for (meth = TYPE_METHODS (self_type);
      for (meth = TYPE_METHODS (self_type);
           ; meth = TREE_CHAIN (meth))
           ; meth = TREE_CHAIN (meth))
        {
        {
          if (method == meth)
          if (method == meth)
            break;
            break;
          if (meth == NULL_TREE)
          if (meth == NULL_TREE)
            fatal_error ("method '%s' not found in class",
            fatal_error ("method '%s' not found in class",
                         IDENTIFIER_POINTER (DECL_NAME (method)));
                         IDENTIFIER_POINTER (DECL_NAME (method)));
          method_index++;
          method_index++;
        }
        }
      method_index *= int_size_in_bytes (method_type_node);
      method_index *= int_size_in_bytes (method_type_node);
      ref = fold_build2 (POINTER_PLUS_EXPR, method_ptr_type_node,
      ref = fold_build2 (POINTER_PLUS_EXPR, method_ptr_type_node,
                         ref, size_int (method_index));
                         ref, size_int (method_index));
      ref = build1 (INDIRECT_REF, method_type_node, ref);
      ref = build1 (INDIRECT_REF, method_type_node, ref);
      func = build3 (COMPONENT_REF, nativecode_ptr_type_node,
      func = build3 (COMPONENT_REF, nativecode_ptr_type_node,
                     ref, lookup_field (&method_type_node, ncode_ident),
                     ref, lookup_field (&method_type_node, ncode_ident),
                     NULL_TREE);
                     NULL_TREE);
    }
    }
  return func;
  return func;
}
}
 
 
tree
tree
invoke_build_dtable (int is_invoke_interface, tree arg_list)
invoke_build_dtable (int is_invoke_interface, tree arg_list)
{
{
  tree dtable, objectref;
  tree dtable, objectref;
 
 
  TREE_VALUE (arg_list) = save_expr (TREE_VALUE (arg_list));
  TREE_VALUE (arg_list) = save_expr (TREE_VALUE (arg_list));
 
 
  /* If we're dealing with interfaces and if the objectref
  /* If we're dealing with interfaces and if the objectref
     argument is an array then get the dispatch table of the class
     argument is an array then get the dispatch table of the class
     Object rather than the one from the objectref.  */
     Object rather than the one from the objectref.  */
  objectref = (is_invoke_interface
  objectref = (is_invoke_interface
               && is_array_type_p (TREE_TYPE (TREE_VALUE (arg_list)))
               && is_array_type_p (TREE_TYPE (TREE_VALUE (arg_list)))
               ? build_class_ref (object_type_node) : TREE_VALUE (arg_list));
               ? build_class_ref (object_type_node) : TREE_VALUE (arg_list));
 
 
  if (dtable_ident == NULL_TREE)
  if (dtable_ident == NULL_TREE)
    dtable_ident = get_identifier ("vtable");
    dtable_ident = get_identifier ("vtable");
  dtable = build_java_indirect_ref (object_type_node, objectref,
  dtable = build_java_indirect_ref (object_type_node, objectref,
                                    flag_check_references);
                                    flag_check_references);
  dtable = build3 (COMPONENT_REF, dtable_ptr_type, dtable,
  dtable = build3 (COMPONENT_REF, dtable_ptr_type, dtable,
                   lookup_field (&object_type_node, dtable_ident), NULL_TREE);
                   lookup_field (&object_type_node, dtable_ident), NULL_TREE);
 
 
  return dtable;
  return dtable;
}
}
 
 
/* Determine the index in SYMBOL_TABLE for a reference to the decl
/* Determine the index in SYMBOL_TABLE for a reference to the decl
   T. If this decl has not been seen before, it will be added to the
   T. If this decl has not been seen before, it will be added to the
   [oa]table_methods. If it has, the existing table slot will be
   [oa]table_methods. If it has, the existing table slot will be
   reused.  */
   reused.  */
 
 
int
int
get_symbol_table_index (tree t, tree special, tree *symbol_table)
get_symbol_table_index (tree t, tree special, tree *symbol_table)
{
{
  int i = 1;
  int i = 1;
  tree method_list;
  tree method_list;
 
 
  if (*symbol_table == NULL_TREE)
  if (*symbol_table == NULL_TREE)
    {
    {
      *symbol_table = build_tree_list (special, t);
      *symbol_table = build_tree_list (special, t);
      return 1;
      return 1;
    }
    }
 
 
  method_list = *symbol_table;
  method_list = *symbol_table;
 
 
  while (1)
  while (1)
    {
    {
      tree value = TREE_VALUE (method_list);
      tree value = TREE_VALUE (method_list);
      tree purpose = TREE_PURPOSE (method_list);
      tree purpose = TREE_PURPOSE (method_list);
      if (value == t && purpose == special)
      if (value == t && purpose == special)
        return i;
        return i;
      i++;
      i++;
      if (TREE_CHAIN (method_list) == NULL_TREE)
      if (TREE_CHAIN (method_list) == NULL_TREE)
        break;
        break;
      else
      else
        method_list = TREE_CHAIN (method_list);
        method_list = TREE_CHAIN (method_list);
    }
    }
 
 
  TREE_CHAIN (method_list) = build_tree_list (special, t);
  TREE_CHAIN (method_list) = build_tree_list (special, t);
  return i;
  return i;
}
}
 
 
tree
tree
build_invokevirtual (tree dtable, tree method, tree special)
build_invokevirtual (tree dtable, tree method, tree special)
{
{
  tree func;
  tree func;
  tree nativecode_ptr_ptr_type_node
  tree nativecode_ptr_ptr_type_node
    = build_pointer_type (nativecode_ptr_type_node);
    = build_pointer_type (nativecode_ptr_type_node);
  tree method_index;
  tree method_index;
  tree otable_index;
  tree otable_index;
 
 
  if (flag_indirect_dispatch)
  if (flag_indirect_dispatch)
    {
    {
      gcc_assert (! CLASS_INTERFACE (TYPE_NAME (DECL_CONTEXT (method))));
      gcc_assert (! CLASS_INTERFACE (TYPE_NAME (DECL_CONTEXT (method))));
 
 
      otable_index
      otable_index
        = build_int_cst (NULL_TREE, get_symbol_table_index
        = build_int_cst (NULL_TREE, get_symbol_table_index
                         (method, special,
                         (method, special,
                          &TYPE_OTABLE_METHODS (output_class)));
                          &TYPE_OTABLE_METHODS (output_class)));
      method_index = build4 (ARRAY_REF, integer_type_node,
      method_index = build4 (ARRAY_REF, integer_type_node,
                             TYPE_OTABLE_DECL (output_class),
                             TYPE_OTABLE_DECL (output_class),
                             otable_index, NULL_TREE, NULL_TREE);
                             otable_index, NULL_TREE, NULL_TREE);
    }
    }
  else
  else
    {
    {
      /* We fetch the DECL_VINDEX field directly here, rather than
      /* We fetch the DECL_VINDEX field directly here, rather than
         using get_method_index().  DECL_VINDEX is the true offset
         using get_method_index().  DECL_VINDEX is the true offset
         from the vtable base to a method, regrdless of any extra
         from the vtable base to a method, regrdless of any extra
         words inserted at the start of the vtable.  */
         words inserted at the start of the vtable.  */
      method_index = DECL_VINDEX (method);
      method_index = DECL_VINDEX (method);
      method_index = size_binop (MULT_EXPR, method_index,
      method_index = size_binop (MULT_EXPR, method_index,
                                 TYPE_SIZE_UNIT (nativecode_ptr_ptr_type_node));
                                 TYPE_SIZE_UNIT (nativecode_ptr_ptr_type_node));
      if (TARGET_VTABLE_USES_DESCRIPTORS)
      if (TARGET_VTABLE_USES_DESCRIPTORS)
        method_index = size_binop (MULT_EXPR, method_index,
        method_index = size_binop (MULT_EXPR, method_index,
                                   size_int (TARGET_VTABLE_USES_DESCRIPTORS));
                                   size_int (TARGET_VTABLE_USES_DESCRIPTORS));
    }
    }
 
 
  func = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (dtable), dtable,
  func = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (dtable), dtable,
                      convert (sizetype, method_index));
                      convert (sizetype, method_index));
 
 
  if (TARGET_VTABLE_USES_DESCRIPTORS)
  if (TARGET_VTABLE_USES_DESCRIPTORS)
    func = build1 (NOP_EXPR, nativecode_ptr_type_node, func);
    func = build1 (NOP_EXPR, nativecode_ptr_type_node, func);
  else
  else
    {
    {
      func = fold_convert (nativecode_ptr_ptr_type_node, func);
      func = fold_convert (nativecode_ptr_ptr_type_node, func);
      func = build1 (INDIRECT_REF, nativecode_ptr_type_node, func);
      func = build1 (INDIRECT_REF, nativecode_ptr_type_node, func);
    }
    }
 
 
  return func;
  return func;
}
}
 
 
static GTY(()) tree class_ident;
static GTY(()) tree class_ident;
tree
tree
build_invokeinterface (tree dtable, tree method)
build_invokeinterface (tree dtable, tree method)
{
{
  tree interface;
  tree interface;
  tree idx;
  tree idx;
 
 
  /* We expand invokeinterface here.  */
  /* We expand invokeinterface here.  */
 
 
  if (class_ident == NULL_TREE)
  if (class_ident == NULL_TREE)
    class_ident = get_identifier ("class");
    class_ident = get_identifier ("class");
 
 
  dtable = build_java_indirect_ref (dtable_type, dtable,
  dtable = build_java_indirect_ref (dtable_type, dtable,
                                    flag_check_references);
                                    flag_check_references);
  dtable = build3 (COMPONENT_REF, class_ptr_type, dtable,
  dtable = build3 (COMPONENT_REF, class_ptr_type, dtable,
                   lookup_field (&dtable_type, class_ident), NULL_TREE);
                   lookup_field (&dtable_type, class_ident), NULL_TREE);
 
 
  interface = DECL_CONTEXT (method);
  interface = DECL_CONTEXT (method);
  gcc_assert (CLASS_INTERFACE (TYPE_NAME (interface)));
  gcc_assert (CLASS_INTERFACE (TYPE_NAME (interface)));
  layout_class_methods (interface);
  layout_class_methods (interface);
 
 
  if (flag_indirect_dispatch)
  if (flag_indirect_dispatch)
    {
    {
      int itable_index
      int itable_index
        = 2 * (get_symbol_table_index
        = 2 * (get_symbol_table_index
               (method, NULL_TREE, &TYPE_ITABLE_METHODS (output_class)));
               (method, NULL_TREE, &TYPE_ITABLE_METHODS (output_class)));
      interface
      interface
        = build4 (ARRAY_REF,
        = build4 (ARRAY_REF,
                 TREE_TYPE (TREE_TYPE (TYPE_ITABLE_DECL (output_class))),
                 TREE_TYPE (TREE_TYPE (TYPE_ITABLE_DECL (output_class))),
                 TYPE_ITABLE_DECL (output_class),
                 TYPE_ITABLE_DECL (output_class),
                  build_int_cst (NULL_TREE, itable_index-1),
                  build_int_cst (NULL_TREE, itable_index-1),
                  NULL_TREE, NULL_TREE);
                  NULL_TREE, NULL_TREE);
      idx
      idx
        = build4 (ARRAY_REF,
        = build4 (ARRAY_REF,
                 TREE_TYPE (TREE_TYPE (TYPE_ITABLE_DECL (output_class))),
                 TREE_TYPE (TREE_TYPE (TYPE_ITABLE_DECL (output_class))),
                 TYPE_ITABLE_DECL (output_class),
                 TYPE_ITABLE_DECL (output_class),
                  build_int_cst (NULL_TREE, itable_index),
                  build_int_cst (NULL_TREE, itable_index),
                  NULL_TREE, NULL_TREE);
                  NULL_TREE, NULL_TREE);
      interface = convert (class_ptr_type, interface);
      interface = convert (class_ptr_type, interface);
      idx = convert (integer_type_node, idx);
      idx = convert (integer_type_node, idx);
    }
    }
  else
  else
    {
    {
      idx = build_int_cst (NULL_TREE,
      idx = build_int_cst (NULL_TREE,
                           get_interface_method_index (method, interface));
                           get_interface_method_index (method, interface));
      interface = build_class_ref (interface);
      interface = build_class_ref (interface);
    }
    }
 
 
  return build_call_nary (ptr_type_node,
  return build_call_nary (ptr_type_node,
                          build_address_of (soft_lookupinterfacemethod_node),
                          build_address_of (soft_lookupinterfacemethod_node),
                          3, dtable, interface, idx);
                          3, dtable, interface, idx);
}
}
 
 
/* Expand one of the invoke_* opcodes.
/* Expand one of the invoke_* opcodes.
   OPCODE is the specific opcode.
   OPCODE is the specific opcode.
   METHOD_REF_INDEX is an index into the constant pool.
   METHOD_REF_INDEX is an index into the constant pool.
   NARGS is the number of arguments, or -1 if not specified. */
   NARGS is the number of arguments, or -1 if not specified. */
 
 
static void
static void
expand_invoke (int opcode, int method_ref_index, int nargs ATTRIBUTE_UNUSED)
expand_invoke (int opcode, int method_ref_index, int nargs ATTRIBUTE_UNUSED)
{
{
  tree method_signature
  tree method_signature
    = COMPONENT_REF_SIGNATURE(&current_jcf->cpool, method_ref_index);
    = COMPONENT_REF_SIGNATURE(&current_jcf->cpool, method_ref_index);
  tree method_name = COMPONENT_REF_NAME (&current_jcf->cpool,
  tree method_name = COMPONENT_REF_NAME (&current_jcf->cpool,
                                         method_ref_index);
                                         method_ref_index);
  tree self_type
  tree self_type
    = get_class_constant (current_jcf,
    = get_class_constant (current_jcf,
                          COMPONENT_REF_CLASS_INDEX(&current_jcf->cpool,
                          COMPONENT_REF_CLASS_INDEX(&current_jcf->cpool,
                          method_ref_index));
                          method_ref_index));
  const char *const self_name
  const char *const self_name
    = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (self_type)));
    = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (self_type)));
  tree call, func, method, arg_list, method_type;
  tree call, func, method, arg_list, method_type;
  tree check = NULL_TREE;
  tree check = NULL_TREE;
 
 
  tree special = NULL_TREE;
  tree special = NULL_TREE;
 
 
  if (! CLASS_LOADED_P (self_type))
  if (! CLASS_LOADED_P (self_type))
    {
    {
      load_class (self_type, 1);
      load_class (self_type, 1);
      safe_layout_class (self_type);
      safe_layout_class (self_type);
      if (TREE_CODE (TYPE_SIZE (self_type)) == ERROR_MARK)
      if (TREE_CODE (TYPE_SIZE (self_type)) == ERROR_MARK)
        fatal_error ("failed to find class '%s'", self_name);
        fatal_error ("failed to find class '%s'", self_name);
    }
    }
  layout_class_methods (self_type);
  layout_class_methods (self_type);
 
 
  if (ID_INIT_P (method_name))
  if (ID_INIT_P (method_name))
    method = lookup_java_constructor (self_type, method_signature);
    method = lookup_java_constructor (self_type, method_signature);
  else
  else
    method = lookup_java_method (self_type, method_name, method_signature);
    method = lookup_java_method (self_type, method_name, method_signature);
 
 
  /* We've found a method in a class other than the one in which it
  /* We've found a method in a class other than the one in which it
     was wanted.  This can happen if, for instance, we're trying to
     was wanted.  This can happen if, for instance, we're trying to
     compile invokespecial super.equals().
     compile invokespecial super.equals().
     FIXME: This is a kludge.  Rather than nullifying the result, we
     FIXME: This is a kludge.  Rather than nullifying the result, we
     should change lookup_java_method() so that it doesn't search the
     should change lookup_java_method() so that it doesn't search the
     superclass chain when we're BC-compiling.  */
     superclass chain when we're BC-compiling.  */
  if (! flag_verify_invocations
  if (! flag_verify_invocations
      && method
      && method
      && ! TYPE_ARRAY_P (self_type)
      && ! TYPE_ARRAY_P (self_type)
      && self_type != DECL_CONTEXT (method))
      && self_type != DECL_CONTEXT (method))
    method = NULL_TREE;
    method = NULL_TREE;
 
 
  /* We've found a method in an interface, but this isn't an interface
  /* We've found a method in an interface, but this isn't an interface
     call.  */
     call.  */
  if (opcode != OPCODE_invokeinterface
  if (opcode != OPCODE_invokeinterface
      && method
      && method
      && (CLASS_INTERFACE (TYPE_NAME (DECL_CONTEXT (method)))))
      && (CLASS_INTERFACE (TYPE_NAME (DECL_CONTEXT (method)))))
    method = NULL_TREE;
    method = NULL_TREE;
 
 
  /* We've found a non-interface method but we are making an
  /* We've found a non-interface method but we are making an
     interface call.  This can happen if the interface overrides a
     interface call.  This can happen if the interface overrides a
     method in Object.  */
     method in Object.  */
  if (! flag_verify_invocations
  if (! flag_verify_invocations
      && opcode == OPCODE_invokeinterface
      && opcode == OPCODE_invokeinterface
      && method
      && method
      && ! CLASS_INTERFACE (TYPE_NAME (DECL_CONTEXT (method))))
      && ! CLASS_INTERFACE (TYPE_NAME (DECL_CONTEXT (method))))
    method = NULL_TREE;
    method = NULL_TREE;
 
 
  if (method == NULL_TREE)
  if (method == NULL_TREE)
    {
    {
      if (flag_verify_invocations || ! flag_indirect_dispatch)
      if (flag_verify_invocations || ! flag_indirect_dispatch)
        {
        {
          error ("class '%s' has no method named '%s' matching signature '%s'",
          error ("class '%s' has no method named '%s' matching signature '%s'",
                 self_name,
                 self_name,
                 IDENTIFIER_POINTER (method_name),
                 IDENTIFIER_POINTER (method_name),
                 IDENTIFIER_POINTER (method_signature));
                 IDENTIFIER_POINTER (method_signature));
        }
        }
      else
      else
        {
        {
          int flags = ACC_PUBLIC;
          int flags = ACC_PUBLIC;
          if (opcode == OPCODE_invokestatic)
          if (opcode == OPCODE_invokestatic)
            flags |= ACC_STATIC;
            flags |= ACC_STATIC;
          if (opcode == OPCODE_invokeinterface)
          if (opcode == OPCODE_invokeinterface)
            {
            {
              flags |= ACC_INTERFACE | ACC_ABSTRACT;
              flags |= ACC_INTERFACE | ACC_ABSTRACT;
              CLASS_INTERFACE (TYPE_NAME (self_type)) = 1;
              CLASS_INTERFACE (TYPE_NAME (self_type)) = 1;
            }
            }
          method = add_method (self_type, flags, method_name,
          method = add_method (self_type, flags, method_name,
                               method_signature);
                               method_signature);
          DECL_ARTIFICIAL (method) = 1;
          DECL_ARTIFICIAL (method) = 1;
          METHOD_DUMMY (method) = 1;
          METHOD_DUMMY (method) = 1;
          layout_class_method (self_type, NULL,
          layout_class_method (self_type, NULL,
                               method, NULL);
                               method, NULL);
        }
        }
    }
    }
 
 
  /* Invoke static can't invoke static/abstract method */
  /* Invoke static can't invoke static/abstract method */
  if (method != NULL_TREE)
  if (method != NULL_TREE)
    {
    {
      if (opcode == OPCODE_invokestatic)
      if (opcode == OPCODE_invokestatic)
        {
        {
          if (!METHOD_STATIC (method))
          if (!METHOD_STATIC (method))
            {
            {
              error ("invokestatic on non static method");
              error ("invokestatic on non static method");
              method = NULL_TREE;
              method = NULL_TREE;
            }
            }
          else if (METHOD_ABSTRACT (method))
          else if (METHOD_ABSTRACT (method))
            {
            {
              error ("invokestatic on abstract method");
              error ("invokestatic on abstract method");
              method = NULL_TREE;
              method = NULL_TREE;
            }
            }
        }
        }
      else
      else
        {
        {
          if (METHOD_STATIC (method))
          if (METHOD_STATIC (method))
            {
            {
              error ("invoke[non-static] on static method");
              error ("invoke[non-static] on static method");
              method = NULL_TREE;
              method = NULL_TREE;
            }
            }
        }
        }
    }
    }
 
 
  if (method == NULL_TREE)
  if (method == NULL_TREE)
    {
    {
      /* If we got here, we emitted an error message above.  So we
      /* If we got here, we emitted an error message above.  So we
         just pop the arguments, push a properly-typed zero, and
         just pop the arguments, push a properly-typed zero, and
         continue.  */
         continue.  */
      method_type = get_type_from_signature (method_signature);
      method_type = get_type_from_signature (method_signature);
      pop_arguments (TYPE_ARG_TYPES (method_type));
      pop_arguments (TYPE_ARG_TYPES (method_type));
      if (opcode != OPCODE_invokestatic)
      if (opcode != OPCODE_invokestatic)
        pop_type (self_type);
        pop_type (self_type);
      method_type = promote_type (TREE_TYPE (method_type));
      method_type = promote_type (TREE_TYPE (method_type));
      push_value (convert (method_type, integer_zero_node));
      push_value (convert (method_type, integer_zero_node));
      return;
      return;
    }
    }
 
 
  method_type = TREE_TYPE (method);
  method_type = TREE_TYPE (method);
  arg_list = pop_arguments (TYPE_ARG_TYPES (method_type));
  arg_list = pop_arguments (TYPE_ARG_TYPES (method_type));
  flush_quick_stack ();
  flush_quick_stack ();
 
 
  maybe_rewrite_invocation (&method, &arg_list, &method_signature,
  maybe_rewrite_invocation (&method, &arg_list, &method_signature,
                            &special);
                            &special);
 
 
  func = NULL_TREE;
  func = NULL_TREE;
  if (opcode == OPCODE_invokestatic)
  if (opcode == OPCODE_invokestatic)
    func = build_known_method_ref (method, method_type, self_type,
    func = build_known_method_ref (method, method_type, self_type,
                                   method_signature, arg_list, special);
                                   method_signature, arg_list, special);
  else if (opcode == OPCODE_invokespecial
  else if (opcode == OPCODE_invokespecial
           || (opcode == OPCODE_invokevirtual
           || (opcode == OPCODE_invokevirtual
               && (METHOD_PRIVATE (method)
               && (METHOD_PRIVATE (method)
                   || METHOD_FINAL (method)
                   || METHOD_FINAL (method)
                   || CLASS_FINAL (TYPE_NAME (self_type)))))
                   || CLASS_FINAL (TYPE_NAME (self_type)))))
    {
    {
      /* If the object for the method call is null, we throw an
      /* If the object for the method call is null, we throw an
         exception.  We don't do this if the object is the current
         exception.  We don't do this if the object is the current
         method's `this'.  In other cases we just rely on an
         method's `this'.  In other cases we just rely on an
         optimization pass to eliminate redundant checks.  FIXME:
         optimization pass to eliminate redundant checks.  FIXME:
         Unfortunately there doesn't seem to be a way to determine
         Unfortunately there doesn't seem to be a way to determine
         what the current method is right now.
         what the current method is right now.
         We do omit the check if we're calling <init>.  */
         We do omit the check if we're calling <init>.  */
      /* We use a SAVE_EXPR here to make sure we only evaluate
      /* We use a SAVE_EXPR here to make sure we only evaluate
         the new `self' expression once.  */
         the new `self' expression once.  */
      tree save_arg = save_expr (TREE_VALUE (arg_list));
      tree save_arg = save_expr (TREE_VALUE (arg_list));
      TREE_VALUE (arg_list) = save_arg;
      TREE_VALUE (arg_list) = save_arg;
      check = java_check_reference (save_arg, ! DECL_INIT_P (method));
      check = java_check_reference (save_arg, ! DECL_INIT_P (method));
      func = build_known_method_ref (method, method_type, self_type,
      func = build_known_method_ref (method, method_type, self_type,
                                     method_signature, arg_list, special);
                                     method_signature, arg_list, special);
    }
    }
  else
  else
    {
    {
      tree dtable = invoke_build_dtable (opcode == OPCODE_invokeinterface,
      tree dtable = invoke_build_dtable (opcode == OPCODE_invokeinterface,
                                         arg_list);
                                         arg_list);
      if (opcode == OPCODE_invokevirtual)
      if (opcode == OPCODE_invokevirtual)
        func = build_invokevirtual (dtable, method, special);
        func = build_invokevirtual (dtable, method, special);
      else
      else
        func = build_invokeinterface (dtable, method);
        func = build_invokeinterface (dtable, method);
    }
    }
 
 
  if (TREE_CODE (func) == ADDR_EXPR)
  if (TREE_CODE (func) == ADDR_EXPR)
    TREE_TYPE (func) = build_pointer_type (method_type);
    TREE_TYPE (func) = build_pointer_type (method_type);
  else
  else
    func = build1 (NOP_EXPR, build_pointer_type (method_type), func);
    func = build1 (NOP_EXPR, build_pointer_type (method_type), func);
 
 
  call = build_call_list (TREE_TYPE (method_type), func, arg_list);
  call = build_call_list (TREE_TYPE (method_type), func, arg_list);
  TREE_SIDE_EFFECTS (call) = 1;
  TREE_SIDE_EFFECTS (call) = 1;
  call = check_for_builtin (method, call);
  call = check_for_builtin (method, call);
 
 
  if (check != NULL_TREE)
  if (check != NULL_TREE)
    {
    {
      call = build2 (COMPOUND_EXPR, TREE_TYPE (call), check, call);
      call = build2 (COMPOUND_EXPR, TREE_TYPE (call), check, call);
      TREE_SIDE_EFFECTS (call) = 1;
      TREE_SIDE_EFFECTS (call) = 1;
    }
    }
 
 
  if (TREE_CODE (TREE_TYPE (method_type)) == VOID_TYPE)
  if (TREE_CODE (TREE_TYPE (method_type)) == VOID_TYPE)
    java_add_stmt (call);
    java_add_stmt (call);
  else
  else
    {
    {
      push_value (call);
      push_value (call);
      flush_quick_stack ();
      flush_quick_stack ();
    }
    }
}
}
 
 
/* Create a stub which will be put into the vtable but which will call
/* Create a stub which will be put into the vtable but which will call
   a JNI function.  */
   a JNI function.  */
 
 
tree
tree
build_jni_stub (tree method)
build_jni_stub (tree method)
{
{
  tree jnifunc, call, args, body, method_sig, arg_types;
  tree jnifunc, call, args, body, method_sig, arg_types;
  tree jniarg0, jniarg1, jniarg2, jniarg3;
  tree jniarg0, jniarg1, jniarg2, jniarg3;
  tree jni_func_type, tem;
  tree jni_func_type, tem;
  tree env_var, res_var = NULL_TREE, block;
  tree env_var, res_var = NULL_TREE, block;
  tree method_args;
  tree method_args;
  tree meth_var;
  tree meth_var;
  tree bind;
  tree bind;
 
 
  int args_size = 0;
  int args_size = 0;
 
 
  tree klass = DECL_CONTEXT (method);
  tree klass = DECL_CONTEXT (method);
  klass = build_class_ref (klass);
  klass = build_class_ref (klass);
 
 
  gcc_assert (METHOD_NATIVE (method) && flag_jni);
  gcc_assert (METHOD_NATIVE (method) && flag_jni);
 
 
  DECL_ARTIFICIAL (method) = 1;
  DECL_ARTIFICIAL (method) = 1;
  DECL_EXTERNAL (method) = 0;
  DECL_EXTERNAL (method) = 0;
 
 
  env_var = build_decl (input_location,
  env_var = build_decl (input_location,
                        VAR_DECL, get_identifier ("env"), ptr_type_node);
                        VAR_DECL, get_identifier ("env"), ptr_type_node);
  DECL_CONTEXT (env_var) = method;
  DECL_CONTEXT (env_var) = method;
 
 
  if (TREE_TYPE (TREE_TYPE (method)) != void_type_node)
  if (TREE_TYPE (TREE_TYPE (method)) != void_type_node)
    {
    {
      res_var = build_decl (input_location, VAR_DECL, get_identifier ("res"),
      res_var = build_decl (input_location, VAR_DECL, get_identifier ("res"),
                            TREE_TYPE (TREE_TYPE (method)));
                            TREE_TYPE (TREE_TYPE (method)));
      DECL_CONTEXT (res_var) = method;
      DECL_CONTEXT (res_var) = method;
      TREE_CHAIN (env_var) = res_var;
      TREE_CHAIN (env_var) = res_var;
    }
    }
 
 
  method_args = DECL_ARGUMENTS (method);
  method_args = DECL_ARGUMENTS (method);
  block = build_block (env_var, NULL_TREE, method_args, NULL_TREE);
  block = build_block (env_var, NULL_TREE, method_args, NULL_TREE);
  TREE_SIDE_EFFECTS (block) = 1;
  TREE_SIDE_EFFECTS (block) = 1;
  TREE_TYPE (block) = TREE_TYPE (TREE_TYPE (method));
  TREE_TYPE (block) = TREE_TYPE (TREE_TYPE (method));
 
 
  /* Compute the local `env' by calling _Jv_GetJNIEnvNewFrame.  */
  /* Compute the local `env' by calling _Jv_GetJNIEnvNewFrame.  */
  body = build2 (MODIFY_EXPR, ptr_type_node, env_var,
  body = build2 (MODIFY_EXPR, ptr_type_node, env_var,
                 build_call_nary (ptr_type_node,
                 build_call_nary (ptr_type_node,
                                  build_address_of (soft_getjnienvnewframe_node),
                                  build_address_of (soft_getjnienvnewframe_node),
                                  1, klass));
                                  1, klass));
 
 
  /* All the arguments to this method become arguments to the
  /* All the arguments to this method become arguments to the
     underlying JNI function.  If we had to wrap object arguments in a
     underlying JNI function.  If we had to wrap object arguments in a
     special way, we would do that here.  */
     special way, we would do that here.  */
  args = NULL_TREE;
  args = NULL_TREE;
  for (tem = method_args; tem != NULL_TREE; tem = TREE_CHAIN (tem))
  for (tem = method_args; tem != NULL_TREE; tem = TREE_CHAIN (tem))
    {
    {
      int arg_bits = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (tem)));
      int arg_bits = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (tem)));
#ifdef PARM_BOUNDARY
#ifdef PARM_BOUNDARY
      arg_bits = (((arg_bits + PARM_BOUNDARY - 1) / PARM_BOUNDARY)
      arg_bits = (((arg_bits + PARM_BOUNDARY - 1) / PARM_BOUNDARY)
                  * PARM_BOUNDARY);
                  * PARM_BOUNDARY);
#endif
#endif
      args_size += (arg_bits / BITS_PER_UNIT);
      args_size += (arg_bits / BITS_PER_UNIT);
 
 
      args = tree_cons (NULL_TREE, tem, args);
      args = tree_cons (NULL_TREE, tem, args);
    }
    }
  args = nreverse (args);
  args = nreverse (args);
  arg_types = TYPE_ARG_TYPES (TREE_TYPE (method));
  arg_types = TYPE_ARG_TYPES (TREE_TYPE (method));
 
 
  /* For a static method the second argument is the class.  For a
  /* For a static method the second argument is the class.  For a
     non-static method the second argument is `this'; that is already
     non-static method the second argument is `this'; that is already
     available in the argument list.  */
     available in the argument list.  */
  if (METHOD_STATIC (method))
  if (METHOD_STATIC (method))
    {
    {
      args_size += int_size_in_bytes (TREE_TYPE (klass));
      args_size += int_size_in_bytes (TREE_TYPE (klass));
      args = tree_cons (NULL_TREE, klass, args);
      args = tree_cons (NULL_TREE, klass, args);
      arg_types = tree_cons (NULL_TREE, object_ptr_type_node, arg_types);
      arg_types = tree_cons (NULL_TREE, object_ptr_type_node, arg_types);
    }
    }
 
 
  /* The JNIEnv structure is the first argument to the JNI function.  */
  /* The JNIEnv structure is the first argument to the JNI function.  */
  args_size += int_size_in_bytes (TREE_TYPE (env_var));
  args_size += int_size_in_bytes (TREE_TYPE (env_var));
  args = tree_cons (NULL_TREE, env_var, args);
  args = tree_cons (NULL_TREE, env_var, args);
  arg_types = tree_cons (NULL_TREE, ptr_type_node, arg_types);
  arg_types = tree_cons (NULL_TREE, ptr_type_node, arg_types);
 
 
  /* We call _Jv_LookupJNIMethod to find the actual underlying
  /* We call _Jv_LookupJNIMethod to find the actual underlying
     function pointer.  _Jv_LookupJNIMethod will throw the appropriate
     function pointer.  _Jv_LookupJNIMethod will throw the appropriate
     exception if this function is not found at runtime.  */
     exception if this function is not found at runtime.  */
  method_sig = build_java_signature (TREE_TYPE (method));
  method_sig = build_java_signature (TREE_TYPE (method));
  jniarg0 = klass;
  jniarg0 = klass;
  jniarg1 = build_utf8_ref (DECL_NAME (method));
  jniarg1 = build_utf8_ref (DECL_NAME (method));
  jniarg2 = build_utf8_ref (unmangle_classname
  jniarg2 = build_utf8_ref (unmangle_classname
                            (IDENTIFIER_POINTER (method_sig),
                            (IDENTIFIER_POINTER (method_sig),
                             IDENTIFIER_LENGTH (method_sig)));
                             IDENTIFIER_LENGTH (method_sig)));
  jniarg3 = build_int_cst (NULL_TREE, args_size);
  jniarg3 = build_int_cst (NULL_TREE, args_size);
 
 
  tem = build_function_type (TREE_TYPE (TREE_TYPE (method)), arg_types);
  tem = build_function_type (TREE_TYPE (TREE_TYPE (method)), arg_types);
 
 
#ifdef MODIFY_JNI_METHOD_CALL
#ifdef MODIFY_JNI_METHOD_CALL
  tem = MODIFY_JNI_METHOD_CALL (tem);
  tem = MODIFY_JNI_METHOD_CALL (tem);
#endif
#endif
 
 
  jni_func_type = build_pointer_type (tem);
  jni_func_type = build_pointer_type (tem);
 
 
  /* Use the actual function type, rather than a generic pointer type,
  /* Use the actual function type, rather than a generic pointer type,
     such that this decl keeps the actual pointer type from being
     such that this decl keeps the actual pointer type from being
     garbage-collected.  If it is, we end up using canonical types
     garbage-collected.  If it is, we end up using canonical types
     with different uids for equivalent function types, and this in
     with different uids for equivalent function types, and this in
     turn causes utf8 identifiers and output order to vary.  */
     turn causes utf8 identifiers and output order to vary.  */
  meth_var = build_decl (input_location,
  meth_var = build_decl (input_location,
                         VAR_DECL, get_identifier ("meth"), jni_func_type);
                         VAR_DECL, get_identifier ("meth"), jni_func_type);
  TREE_STATIC (meth_var) = 1;
  TREE_STATIC (meth_var) = 1;
  TREE_PUBLIC (meth_var) = 0;
  TREE_PUBLIC (meth_var) = 0;
  DECL_EXTERNAL (meth_var) = 0;
  DECL_EXTERNAL (meth_var) = 0;
  DECL_CONTEXT (meth_var) = method;
  DECL_CONTEXT (meth_var) = method;
  DECL_ARTIFICIAL (meth_var) = 1;
  DECL_ARTIFICIAL (meth_var) = 1;
  DECL_INITIAL (meth_var) = null_pointer_node;
  DECL_INITIAL (meth_var) = null_pointer_node;
  TREE_USED (meth_var) = 1;
  TREE_USED (meth_var) = 1;
  chainon (env_var, meth_var);
  chainon (env_var, meth_var);
  build_result_decl (method);
  build_result_decl (method);
 
 
  jnifunc = build3 (COND_EXPR, jni_func_type,
  jnifunc = build3 (COND_EXPR, jni_func_type,
                    build2 (NE_EXPR, boolean_type_node,
                    build2 (NE_EXPR, boolean_type_node,
                            meth_var, build_int_cst (TREE_TYPE (meth_var), 0)),
                            meth_var, build_int_cst (TREE_TYPE (meth_var), 0)),
                    meth_var,
                    meth_var,
                    build2 (MODIFY_EXPR, jni_func_type, meth_var,
                    build2 (MODIFY_EXPR, jni_func_type, meth_var,
                            build1
                            build1
                            (NOP_EXPR, jni_func_type,
                            (NOP_EXPR, jni_func_type,
                             build_call_nary (ptr_type_node,
                             build_call_nary (ptr_type_node,
                                              build_address_of
                                              build_address_of
                                              (soft_lookupjnimethod_node),
                                              (soft_lookupjnimethod_node),
                                              4,
                                              4,
                                              jniarg0, jniarg1,
                                              jniarg0, jniarg1,
                                              jniarg2, jniarg3))));
                                              jniarg2, jniarg3))));
 
 
  /* Now we make the actual JNI call via the resulting function
  /* Now we make the actual JNI call via the resulting function
     pointer.    */
     pointer.    */
  call = build_call_list (TREE_TYPE (TREE_TYPE (method)),
  call = build_call_list (TREE_TYPE (TREE_TYPE (method)),
                          jnifunc, args);
                          jnifunc, args);
 
 
  /* If the JNI call returned a result, capture it here.  If we had to
  /* If the JNI call returned a result, capture it here.  If we had to
     unwrap JNI object results, we would do that here.  */
     unwrap JNI object results, we would do that here.  */
  if (res_var != NULL_TREE)
  if (res_var != NULL_TREE)
    {
    {
      /* If the call returns an object, it may return a JNI weak
      /* If the call returns an object, it may return a JNI weak
         reference, in which case we must unwrap it.  */
         reference, in which case we must unwrap it.  */
      if (! JPRIMITIVE_TYPE_P (TREE_TYPE (TREE_TYPE (method))))
      if (! JPRIMITIVE_TYPE_P (TREE_TYPE (TREE_TYPE (method))))
        call = build_call_nary (TREE_TYPE (TREE_TYPE (method)),
        call = build_call_nary (TREE_TYPE (TREE_TYPE (method)),
                                build_address_of (soft_unwrapjni_node),
                                build_address_of (soft_unwrapjni_node),
                                1, call);
                                1, call);
      call = build2 (MODIFY_EXPR, TREE_TYPE (TREE_TYPE (method)),
      call = build2 (MODIFY_EXPR, TREE_TYPE (TREE_TYPE (method)),
                     res_var, call);
                     res_var, call);
    }
    }
 
 
  TREE_SIDE_EFFECTS (call) = 1;
  TREE_SIDE_EFFECTS (call) = 1;
 
 
  body = build2 (COMPOUND_EXPR, void_type_node, body, call);
  body = build2 (COMPOUND_EXPR, void_type_node, body, call);
  TREE_SIDE_EFFECTS (body) = 1;
  TREE_SIDE_EFFECTS (body) = 1;
 
 
  /* Now free the environment we allocated.  */
  /* Now free the environment we allocated.  */
  call = build_call_nary (ptr_type_node,
  call = build_call_nary (ptr_type_node,
                          build_address_of (soft_jnipopsystemframe_node),
                          build_address_of (soft_jnipopsystemframe_node),
                          1, env_var);
                          1, env_var);
  TREE_SIDE_EFFECTS (call) = 1;
  TREE_SIDE_EFFECTS (call) = 1;
  body = build2 (COMPOUND_EXPR, void_type_node, body, call);
  body = build2 (COMPOUND_EXPR, void_type_node, body, call);
  TREE_SIDE_EFFECTS (body) = 1;
  TREE_SIDE_EFFECTS (body) = 1;
 
 
  /* Finally, do the return.  */
  /* Finally, do the return.  */
  if (res_var != NULL_TREE)
  if (res_var != NULL_TREE)
    {
    {
      tree drt;
      tree drt;
      gcc_assert (DECL_RESULT (method));
      gcc_assert (DECL_RESULT (method));
      /* Make sure we copy the result variable to the actual
      /* Make sure we copy the result variable to the actual
         result.  We use the type of the DECL_RESULT because it
         result.  We use the type of the DECL_RESULT because it
         might be different from the return type of the function:
         might be different from the return type of the function:
         it might be promoted.  */
         it might be promoted.  */
      drt = TREE_TYPE (DECL_RESULT (method));
      drt = TREE_TYPE (DECL_RESULT (method));
      if (drt != TREE_TYPE (res_var))
      if (drt != TREE_TYPE (res_var))
        res_var = build1 (CONVERT_EXPR, drt, res_var);
        res_var = build1 (CONVERT_EXPR, drt, res_var);
      res_var = build2 (MODIFY_EXPR, drt, DECL_RESULT (method), res_var);
      res_var = build2 (MODIFY_EXPR, drt, DECL_RESULT (method), res_var);
      TREE_SIDE_EFFECTS (res_var) = 1;
      TREE_SIDE_EFFECTS (res_var) = 1;
    }
    }
 
 
  body = build2 (COMPOUND_EXPR, void_type_node, body,
  body = build2 (COMPOUND_EXPR, void_type_node, body,
                 build1 (RETURN_EXPR, void_type_node, res_var));
                 build1 (RETURN_EXPR, void_type_node, res_var));
  TREE_SIDE_EFFECTS (body) = 1;
  TREE_SIDE_EFFECTS (body) = 1;
 
 
  /* Prepend class initialization for static methods reachable from
  /* Prepend class initialization for static methods reachable from
     other classes.  */
     other classes.  */
  if (METHOD_STATIC (method)
  if (METHOD_STATIC (method)
      && (! METHOD_PRIVATE (method)
      && (! METHOD_PRIVATE (method)
          || INNER_CLASS_P (DECL_CONTEXT (method))))
          || INNER_CLASS_P (DECL_CONTEXT (method))))
    {
    {
      tree init = build_call_expr (soft_initclass_node, 1,
      tree init = build_call_expr (soft_initclass_node, 1,
                                   klass);
                                   klass);
      body = build2 (COMPOUND_EXPR, void_type_node, init, body);
      body = build2 (COMPOUND_EXPR, void_type_node, init, body);
      TREE_SIDE_EFFECTS (body) = 1;
      TREE_SIDE_EFFECTS (body) = 1;
    }
    }
 
 
  bind = build3 (BIND_EXPR, void_type_node, BLOCK_VARS (block),
  bind = build3 (BIND_EXPR, void_type_node, BLOCK_VARS (block),
                 body, block);
                 body, block);
  return bind;
  return bind;
}
}
 
 
 
 
/* Given lvalue EXP, return a volatile expression that references the
/* Given lvalue EXP, return a volatile expression that references the
   same object.  */
   same object.  */
 
 
tree
tree
java_modify_addr_for_volatile (tree exp)
java_modify_addr_for_volatile (tree exp)
{
{
  tree exp_type = TREE_TYPE (exp);
  tree exp_type = TREE_TYPE (exp);
  tree v_type
  tree v_type
    = build_qualified_type (exp_type,
    = build_qualified_type (exp_type,
                            TYPE_QUALS (exp_type) | TYPE_QUAL_VOLATILE);
                            TYPE_QUALS (exp_type) | TYPE_QUAL_VOLATILE);
  tree addr = build_fold_addr_expr (exp);
  tree addr = build_fold_addr_expr (exp);
  v_type = build_pointer_type (v_type);
  v_type = build_pointer_type (v_type);
  addr = fold_convert (v_type, addr);
  addr = fold_convert (v_type, addr);
  exp = build_fold_indirect_ref (addr);
  exp = build_fold_indirect_ref (addr);
  return exp;
  return exp;
}
}
 
 
 
 
/* Expand an operation to extract from or store into a field.
/* Expand an operation to extract from or store into a field.
   IS_STATIC is 1 iff the field is static.
   IS_STATIC is 1 iff the field is static.
   IS_PUTTING is 1 for putting into a field;  0 for getting from the field.
   IS_PUTTING is 1 for putting into a field;  0 for getting from the field.
   FIELD_REF_INDEX is an index into the constant pool.  */
   FIELD_REF_INDEX is an index into the constant pool.  */
 
 
static void
static void
expand_java_field_op (int is_static, int is_putting, int field_ref_index)
expand_java_field_op (int is_static, int is_putting, int field_ref_index)
{
{
  tree self_type
  tree self_type
    = get_class_constant (current_jcf,
    = get_class_constant (current_jcf,
                          COMPONENT_REF_CLASS_INDEX (&current_jcf->cpool,
                          COMPONENT_REF_CLASS_INDEX (&current_jcf->cpool,
                          field_ref_index));
                          field_ref_index));
  const char *self_name
  const char *self_name
    = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (self_type)));
    = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (self_type)));
  tree field_name = COMPONENT_REF_NAME (&current_jcf->cpool, field_ref_index);
  tree field_name = COMPONENT_REF_NAME (&current_jcf->cpool, field_ref_index);
  tree field_signature = COMPONENT_REF_SIGNATURE (&current_jcf->cpool,
  tree field_signature = COMPONENT_REF_SIGNATURE (&current_jcf->cpool,
                                                  field_ref_index);
                                                  field_ref_index);
  tree field_type = get_type_from_signature (field_signature);
  tree field_type = get_type_from_signature (field_signature);
  tree new_value = is_putting ? pop_value (field_type) : NULL_TREE;
  tree new_value = is_putting ? pop_value (field_type) : NULL_TREE;
  tree field_ref;
  tree field_ref;
  int is_error = 0;
  int is_error = 0;
  tree original_self_type = self_type;
  tree original_self_type = self_type;
  tree field_decl;
  tree field_decl;
  tree modify_expr;
  tree modify_expr;
 
 
  if (! CLASS_LOADED_P (self_type))
  if (! CLASS_LOADED_P (self_type))
    load_class (self_type, 1);
    load_class (self_type, 1);
  field_decl = lookup_field (&self_type, field_name);
  field_decl = lookup_field (&self_type, field_name);
  if (field_decl == error_mark_node)
  if (field_decl == error_mark_node)
    {
    {
      is_error = 1;
      is_error = 1;
    }
    }
  else if (field_decl == NULL_TREE)
  else if (field_decl == NULL_TREE)
    {
    {
      if (! flag_verify_invocations)
      if (! flag_verify_invocations)
        {
        {
          int flags = ACC_PUBLIC;
          int flags = ACC_PUBLIC;
          if (is_static)
          if (is_static)
            flags |= ACC_STATIC;
            flags |= ACC_STATIC;
          self_type = original_self_type;
          self_type = original_self_type;
          field_decl = add_field (original_self_type, field_name,
          field_decl = add_field (original_self_type, field_name,
                                  field_type, flags);
                                  field_type, flags);
          DECL_ARTIFICIAL (field_decl) = 1;
          DECL_ARTIFICIAL (field_decl) = 1;
          DECL_IGNORED_P (field_decl) = 1;
          DECL_IGNORED_P (field_decl) = 1;
#if 0
#if 0
          /* FIXME: We should be pessimistic about volatility.  We
          /* FIXME: We should be pessimistic about volatility.  We
             don't know one way or another, but this is safe.
             don't know one way or another, but this is safe.
             However, doing this has bad effects on code quality.  We
             However, doing this has bad effects on code quality.  We
             need to look at better ways to do this.  */
             need to look at better ways to do this.  */
          TREE_THIS_VOLATILE (field_decl) = 1;
          TREE_THIS_VOLATILE (field_decl) = 1;
#endif
#endif
        }
        }
      else
      else
        {
        {
          error ("missing field '%s' in '%s'",
          error ("missing field '%s' in '%s'",
                 IDENTIFIER_POINTER (field_name), self_name);
                 IDENTIFIER_POINTER (field_name), self_name);
          is_error = 1;
          is_error = 1;
      }
      }
    }
    }
  else if (build_java_signature (TREE_TYPE (field_decl)) != field_signature)
  else if (build_java_signature (TREE_TYPE (field_decl)) != field_signature)
    {
    {
      error ("mismatching signature for field '%s' in '%s'",
      error ("mismatching signature for field '%s' in '%s'",
             IDENTIFIER_POINTER (field_name), self_name);
             IDENTIFIER_POINTER (field_name), self_name);
      is_error = 1;
      is_error = 1;
    }
    }
  field_ref = is_static ? NULL_TREE : pop_value (self_type);
  field_ref = is_static ? NULL_TREE : pop_value (self_type);
  if (is_error)
  if (is_error)
    {
    {
      if (! is_putting)
      if (! is_putting)
        push_value (convert (field_type, integer_zero_node));
        push_value (convert (field_type, integer_zero_node));
      flush_quick_stack ();
      flush_quick_stack ();
      return;
      return;
    }
    }
 
 
  field_ref = build_field_ref (field_ref, self_type, field_name);
  field_ref = build_field_ref (field_ref, self_type, field_name);
  if (is_static
  if (is_static
      && ! flag_indirect_dispatch)
      && ! flag_indirect_dispatch)
    {
    {
      tree context = DECL_CONTEXT (field_ref);
      tree context = DECL_CONTEXT (field_ref);
      if (context != self_type && CLASS_INTERFACE (TYPE_NAME (context)))
      if (context != self_type && CLASS_INTERFACE (TYPE_NAME (context)))
        field_ref = build_class_init (context, field_ref);
        field_ref = build_class_init (context, field_ref);
      else
      else
        field_ref = build_class_init (self_type, field_ref);
        field_ref = build_class_init (self_type, field_ref);
    }
    }
  if (is_putting)
  if (is_putting)
    {
    {
      flush_quick_stack ();
      flush_quick_stack ();
      if (FIELD_FINAL (field_decl))
      if (FIELD_FINAL (field_decl))
        {
        {
          if (DECL_CONTEXT (field_decl) != current_class)
          if (DECL_CONTEXT (field_decl) != current_class)
            error ("assignment to final field %q+D not in field's class",
            error ("assignment to final field %q+D not in field's class",
                   field_decl);
                   field_decl);
          /* We used to check for assignments to final fields not
          /* We used to check for assignments to final fields not
             occurring in the class initializer or in a constructor
             occurring in the class initializer or in a constructor
             here.  However, this constraint doesn't seem to be
             here.  However, this constraint doesn't seem to be
             enforced by the JVM.  */
             enforced by the JVM.  */
        }
        }
 
 
      if (TREE_THIS_VOLATILE (field_decl))
      if (TREE_THIS_VOLATILE (field_decl))
        field_ref = java_modify_addr_for_volatile (field_ref);
        field_ref = java_modify_addr_for_volatile (field_ref);
 
 
      modify_expr = build2 (MODIFY_EXPR, TREE_TYPE (field_ref),
      modify_expr = build2 (MODIFY_EXPR, TREE_TYPE (field_ref),
                            field_ref, new_value);
                            field_ref, new_value);
 
 
      if (TREE_THIS_VOLATILE (field_decl))
      if (TREE_THIS_VOLATILE (field_decl))
        java_add_stmt
        java_add_stmt
          (build_call_expr (built_in_decls[BUILT_IN_SYNCHRONIZE], 0));
          (build_call_expr (built_in_decls[BUILT_IN_SYNCHRONIZE], 0));
 
 
      java_add_stmt (modify_expr);
      java_add_stmt (modify_expr);
    }
    }
  else
  else
    {
    {
      tree temp = build_decl (input_location,
      tree temp = build_decl (input_location,
                              VAR_DECL, NULL_TREE, TREE_TYPE (field_ref));
                              VAR_DECL, NULL_TREE, TREE_TYPE (field_ref));
      java_add_local_var (temp);
      java_add_local_var (temp);
 
 
      if (TREE_THIS_VOLATILE (field_decl))
      if (TREE_THIS_VOLATILE (field_decl))
        field_ref = java_modify_addr_for_volatile (field_ref);
        field_ref = java_modify_addr_for_volatile (field_ref);
 
 
      modify_expr
      modify_expr
        = build2 (MODIFY_EXPR, TREE_TYPE (field_ref), temp, field_ref);
        = build2 (MODIFY_EXPR, TREE_TYPE (field_ref), temp, field_ref);
      java_add_stmt (modify_expr);
      java_add_stmt (modify_expr);
 
 
      if (TREE_THIS_VOLATILE (field_decl))
      if (TREE_THIS_VOLATILE (field_decl))
        java_add_stmt
        java_add_stmt
          (build_call_expr (built_in_decls[BUILT_IN_SYNCHRONIZE], 0));
          (build_call_expr (built_in_decls[BUILT_IN_SYNCHRONIZE], 0));
 
 
      push_value (temp);
      push_value (temp);
    }
    }
  TREE_THIS_VOLATILE (field_ref) = TREE_THIS_VOLATILE (field_decl);
  TREE_THIS_VOLATILE (field_ref) = TREE_THIS_VOLATILE (field_decl);
}
}
 
 
static void
static void
load_type_state (int pc)
load_type_state (int pc)
{
{
  int i;
  int i;
  tree vec = VEC_index (tree, type_states, pc);
  tree vec = VEC_index (tree, type_states, pc);
  int cur_length = TREE_VEC_LENGTH (vec);
  int cur_length = TREE_VEC_LENGTH (vec);
  stack_pointer = cur_length - DECL_MAX_LOCALS(current_function_decl);
  stack_pointer = cur_length - DECL_MAX_LOCALS(current_function_decl);
  for (i = 0; i < cur_length; i++)
  for (i = 0; i < cur_length; i++)
    type_map [i] = TREE_VEC_ELT (vec, i);
    type_map [i] = TREE_VEC_ELT (vec, i);
}
}
 
 
/* Go over METHOD's bytecode and note instruction starts in
/* Go over METHOD's bytecode and note instruction starts in
   instruction_bits[].  */
   instruction_bits[].  */
 
 
void
void
note_instructions (JCF *jcf, tree method)
note_instructions (JCF *jcf, tree method)
{
{
  int PC;
  int PC;
  unsigned char* byte_ops;
  unsigned char* byte_ops;
  long length = DECL_CODE_LENGTH (method);
  long length = DECL_CODE_LENGTH (method);
 
 
  int saw_index;
  int saw_index;
  jint INT_temp;
  jint INT_temp;
 
 
#undef RET /* Defined by config/i386/i386.h */
#undef RET /* Defined by config/i386/i386.h */
#undef PTR
#undef PTR
#define BCODE byte_ops
#define BCODE byte_ops
#define BYTE_type_node byte_type_node
#define BYTE_type_node byte_type_node
#define SHORT_type_node short_type_node
#define SHORT_type_node short_type_node
#define INT_type_node int_type_node
#define INT_type_node int_type_node
#define LONG_type_node long_type_node
#define LONG_type_node long_type_node
#define CHAR_type_node char_type_node
#define CHAR_type_node char_type_node
#define PTR_type_node ptr_type_node
#define PTR_type_node ptr_type_node
#define FLOAT_type_node float_type_node
#define FLOAT_type_node float_type_node
#define DOUBLE_type_node double_type_node
#define DOUBLE_type_node double_type_node
#define VOID_type_node void_type_node
#define VOID_type_node void_type_node
#define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
#define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
#define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
#define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
#define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
#define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
#define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
#define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
 
 
#define CHECK_PC_IN_RANGE(PC) ((void)1) /* Already handled by verifier. */
#define CHECK_PC_IN_RANGE(PC) ((void)1) /* Already handled by verifier. */
 
 
  JCF_SEEK (jcf, DECL_CODE_OFFSET (method));
  JCF_SEEK (jcf, DECL_CODE_OFFSET (method));
  byte_ops = jcf->read_ptr;
  byte_ops = jcf->read_ptr;
  instruction_bits = XRESIZEVAR (char, instruction_bits, length + 1);
  instruction_bits = XRESIZEVAR (char, instruction_bits, length + 1);
  memset (instruction_bits, 0, length + 1);
  memset (instruction_bits, 0, length + 1);
  type_states = VEC_alloc (tree, gc, length + 1);
  type_states = VEC_alloc (tree, gc, length + 1);
  VEC_safe_grow_cleared (tree, gc, type_states, length + 1);
  VEC_safe_grow_cleared (tree, gc, type_states, length + 1);
 
 
  /* This pass figures out which PC can be the targets of jumps. */
  /* This pass figures out which PC can be the targets of jumps. */
  for (PC = 0; PC < length;)
  for (PC = 0; PC < length;)
    {
    {
      int oldpc = PC; /* PC at instruction start. */
      int oldpc = PC; /* PC at instruction start. */
      instruction_bits [PC] |=  BCODE_INSTRUCTION_START;
      instruction_bits [PC] |=  BCODE_INSTRUCTION_START;
      switch (byte_ops[PC++])
      switch (byte_ops[PC++])
        {
        {
#define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
#define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
        case OPCODE: \
        case OPCODE: \
          PRE_##OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
          PRE_##OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
          break;
          break;
 
 
#define NOTE_LABEL(PC) note_label(oldpc, PC)
#define NOTE_LABEL(PC) note_label(oldpc, PC)
 
 
#define PRE_PUSHC(OPERAND_TYPE, OPERAND_VALUE) (void)(OPERAND_VALUE);
#define PRE_PUSHC(OPERAND_TYPE, OPERAND_VALUE) (void)(OPERAND_VALUE);
#define PRE_LOAD(OPERAND_TYPE, OPERAND_VALUE) (void)(OPERAND_VALUE);
#define PRE_LOAD(OPERAND_TYPE, OPERAND_VALUE) (void)(OPERAND_VALUE);
#define PRE_STORE(OPERAND_TYPE, OPERAND_VALUE) (void)(OPERAND_VALUE);
#define PRE_STORE(OPERAND_TYPE, OPERAND_VALUE) (void)(OPERAND_VALUE);
#define PRE_STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
#define PRE_STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
#define PRE_UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
#define PRE_UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
#define PRE_BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
#define PRE_BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
#define PRE_CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
#define PRE_CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
#define PRE_CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
#define PRE_CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
 
 
#define PRE_SPECIAL(OPERAND_TYPE, INSTRUCTION) \
#define PRE_SPECIAL(OPERAND_TYPE, INSTRUCTION) \
  PRE_SPECIAL_##INSTRUCTION(OPERAND_TYPE)
  PRE_SPECIAL_##INSTRUCTION(OPERAND_TYPE)
#define PRE_SPECIAL_IINC(OPERAND_TYPE) \
#define PRE_SPECIAL_IINC(OPERAND_TYPE) \
  ((void) IMMEDIATE_u1, (void) IMMEDIATE_s1)
  ((void) IMMEDIATE_u1, (void) IMMEDIATE_s1)
#define PRE_SPECIAL_ENTER(IGNORE) /* nothing */
#define PRE_SPECIAL_ENTER(IGNORE) /* nothing */
#define PRE_SPECIAL_EXIT(IGNORE) /* nothing */
#define PRE_SPECIAL_EXIT(IGNORE) /* nothing */
#define PRE_SPECIAL_THROW(IGNORE) /* nothing */
#define PRE_SPECIAL_THROW(IGNORE) /* nothing */
#define PRE_SPECIAL_BREAK(IGNORE) /* nothing */
#define PRE_SPECIAL_BREAK(IGNORE) /* nothing */
 
 
/* two forms of wide instructions */
/* two forms of wide instructions */
#define PRE_SPECIAL_WIDE(IGNORE) \
#define PRE_SPECIAL_WIDE(IGNORE) \
  { \
  { \
    int modified_opcode = IMMEDIATE_u1; \
    int modified_opcode = IMMEDIATE_u1; \
    if (modified_opcode == OPCODE_iinc) \
    if (modified_opcode == OPCODE_iinc) \
      { \
      { \
        (void) IMMEDIATE_u2;    /* indexbyte1 and indexbyte2 */ \
        (void) IMMEDIATE_u2;    /* indexbyte1 and indexbyte2 */ \
        (void) IMMEDIATE_s2;    /* constbyte1 and constbyte2 */ \
        (void) IMMEDIATE_s2;    /* constbyte1 and constbyte2 */ \
      } \
      } \
    else \
    else \
      { \
      { \
        (void) IMMEDIATE_u2;    /* indexbyte1 and indexbyte2 */ \
        (void) IMMEDIATE_u2;    /* indexbyte1 and indexbyte2 */ \
      } \
      } \
  }
  }
 
 
#define PRE_IMPL(IGNORE1, IGNORE2) /* nothing */
#define PRE_IMPL(IGNORE1, IGNORE2) /* nothing */
 
 
#define PRE_MONITOR(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
#define PRE_MONITOR(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
 
 
#define PRE_RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
#define PRE_RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
#define PRE_ARRAY(OPERAND_TYPE, SUBOP) \
#define PRE_ARRAY(OPERAND_TYPE, SUBOP) \
          PRE_ARRAY_##SUBOP(OPERAND_TYPE)
          PRE_ARRAY_##SUBOP(OPERAND_TYPE)
#define PRE_ARRAY_LOAD(TYPE) /* nothing */
#define PRE_ARRAY_LOAD(TYPE) /* nothing */
#define PRE_ARRAY_STORE(TYPE) /* nothing */
#define PRE_ARRAY_STORE(TYPE) /* nothing */
#define PRE_ARRAY_LENGTH(TYPE) /* nothing */
#define PRE_ARRAY_LENGTH(TYPE) /* nothing */
#define PRE_ARRAY_NEW(TYPE) PRE_ARRAY_NEW_##TYPE
#define PRE_ARRAY_NEW(TYPE) PRE_ARRAY_NEW_##TYPE
#define PRE_ARRAY_NEW_NUM ((void) IMMEDIATE_u1)
#define PRE_ARRAY_NEW_NUM ((void) IMMEDIATE_u1)
#define PRE_ARRAY_NEW_PTR ((void) IMMEDIATE_u2)
#define PRE_ARRAY_NEW_PTR ((void) IMMEDIATE_u2)
#define PRE_ARRAY_NEW_MULTI ((void) IMMEDIATE_u2, (void) IMMEDIATE_u1)
#define PRE_ARRAY_NEW_MULTI ((void) IMMEDIATE_u2, (void) IMMEDIATE_u1)
 
 
#define PRE_TEST(OPERAND_TYPE, OPERAND_VALUE) NOTE_LABEL (oldpc+IMMEDIATE_s2)
#define PRE_TEST(OPERAND_TYPE, OPERAND_VALUE) NOTE_LABEL (oldpc+IMMEDIATE_s2)
#define PRE_COND(OPERAND_TYPE, OPERAND_VALUE) NOTE_LABEL (oldpc+IMMEDIATE_s2)
#define PRE_COND(OPERAND_TYPE, OPERAND_VALUE) NOTE_LABEL (oldpc+IMMEDIATE_s2)
#define PRE_BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
#define PRE_BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
  saw_index = 0;  INT_temp = (OPERAND_VALUE); \
  saw_index = 0;  INT_temp = (OPERAND_VALUE); \
  if (!saw_index)  NOTE_LABEL(oldpc + INT_temp);
  if (!saw_index)  NOTE_LABEL(oldpc + INT_temp);
#define PRE_JSR(OPERAND_TYPE, OPERAND_VALUE) \
#define PRE_JSR(OPERAND_TYPE, OPERAND_VALUE) \
  saw_index = 0;  INT_temp = (OPERAND_VALUE); \
  saw_index = 0;  INT_temp = (OPERAND_VALUE); \
  NOTE_LABEL (PC); \
  NOTE_LABEL (PC); \
  if (!saw_index)  NOTE_LABEL(oldpc + INT_temp);
  if (!saw_index)  NOTE_LABEL(oldpc + INT_temp);
 
 
#define PRE_RET(OPERAND_TYPE, OPERAND_VALUE)  (void)(OPERAND_VALUE)
#define PRE_RET(OPERAND_TYPE, OPERAND_VALUE)  (void)(OPERAND_VALUE)
 
 
#define PRE_SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
#define PRE_SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
  PC = (PC + 3) / 4 * 4; PRE_##TABLE_OR_LOOKUP##_SWITCH
  PC = (PC + 3) / 4 * 4; PRE_##TABLE_OR_LOOKUP##_SWITCH
 
 
#define PRE_LOOKUP_SWITCH                                               \
#define PRE_LOOKUP_SWITCH                                               \
  { jint default_offset = IMMEDIATE_s4;  jint npairs = IMMEDIATE_s4;    \
  { jint default_offset = IMMEDIATE_s4;  jint npairs = IMMEDIATE_s4;    \
    NOTE_LABEL (default_offset+oldpc);                                  \
    NOTE_LABEL (default_offset+oldpc);                                  \
    if (npairs >= 0)                                                     \
    if (npairs >= 0)                                                     \
      while (--npairs >= 0) {                                            \
      while (--npairs >= 0) {                                            \
       jint match ATTRIBUTE_UNUSED = IMMEDIATE_s4;                      \
       jint match ATTRIBUTE_UNUSED = IMMEDIATE_s4;                      \
       jint offset = IMMEDIATE_s4;                                      \
       jint offset = IMMEDIATE_s4;                                      \
       NOTE_LABEL (offset+oldpc); }                                     \
       NOTE_LABEL (offset+oldpc); }                                     \
  }
  }
 
 
#define PRE_TABLE_SWITCH                                \
#define PRE_TABLE_SWITCH                                \
  { jint default_offset = IMMEDIATE_s4;                 \
  { jint default_offset = IMMEDIATE_s4;                 \
    jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4;  \
    jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4;  \
    NOTE_LABEL (default_offset+oldpc);                  \
    NOTE_LABEL (default_offset+oldpc);                  \
    if (low <= high)                                    \
    if (low <= high)                                    \
     while (low++ <= high) {                            \
     while (low++ <= high) {                            \
       jint offset = IMMEDIATE_s4;                      \
       jint offset = IMMEDIATE_s4;                      \
       NOTE_LABEL (offset+oldpc); }                     \
       NOTE_LABEL (offset+oldpc); }                     \
  }
  }
 
 
#define PRE_FIELD(MAYBE_STATIC, PUT_OR_GET) (void)(IMMEDIATE_u2);
#define PRE_FIELD(MAYBE_STATIC, PUT_OR_GET) (void)(IMMEDIATE_u2);
#define PRE_OBJECT(MAYBE_STATIC, PUT_OR_GET) (void)(IMMEDIATE_u2);
#define PRE_OBJECT(MAYBE_STATIC, PUT_OR_GET) (void)(IMMEDIATE_u2);
#define PRE_INVOKE(MAYBE_STATIC, IS_INTERFACE) \
#define PRE_INVOKE(MAYBE_STATIC, IS_INTERFACE) \
  (void)(IMMEDIATE_u2); \
  (void)(IMMEDIATE_u2); \
  PC += 2 * IS_INTERFACE /* for invokeinterface */;
  PC += 2 * IS_INTERFACE /* for invokeinterface */;
 
 
#include "javaop.def"
#include "javaop.def"
#undef JAVAOP
#undef JAVAOP
        }
        }
    } /* for */
    } /* for */
}
}
 
 
void
void
expand_byte_code (JCF *jcf, tree method)
expand_byte_code (JCF *jcf, tree method)
{
{
  int PC;
  int PC;
  int i;
  int i;
  const unsigned char *linenumber_pointer;
  const unsigned char *linenumber_pointer;
  int dead_code_index = -1;
  int dead_code_index = -1;
  unsigned char* byte_ops;
  unsigned char* byte_ops;
  long length = DECL_CODE_LENGTH (method);
  long length = DECL_CODE_LENGTH (method);
  location_t max_location = input_location;
  location_t max_location = input_location;
 
 
  stack_pointer = 0;
  stack_pointer = 0;
  JCF_SEEK (jcf, DECL_CODE_OFFSET (method));
  JCF_SEEK (jcf, DECL_CODE_OFFSET (method));
  byte_ops = jcf->read_ptr;
  byte_ops = jcf->read_ptr;
 
 
  /* We make an initial pass of the line number table, to note
  /* We make an initial pass of the line number table, to note
     which instructions have associated line number entries. */
     which instructions have associated line number entries. */
  linenumber_pointer = linenumber_table;
  linenumber_pointer = linenumber_table;
  for (i = 0; i < linenumber_count; i++)
  for (i = 0; i < linenumber_count; i++)
    {
    {
      int pc = GET_u2 (linenumber_pointer);
      int pc = GET_u2 (linenumber_pointer);
      linenumber_pointer += 4;
      linenumber_pointer += 4;
      if (pc >= length)
      if (pc >= length)
        warning (0, "invalid PC in line number table");
        warning (0, "invalid PC in line number table");
      else
      else
        {
        {
          if ((instruction_bits[pc] & BCODE_HAS_LINENUMBER) != 0)
          if ((instruction_bits[pc] & BCODE_HAS_LINENUMBER) != 0)
            instruction_bits[pc] |= BCODE_HAS_MULTI_LINENUMBERS;
            instruction_bits[pc] |= BCODE_HAS_MULTI_LINENUMBERS;
          instruction_bits[pc] |= BCODE_HAS_LINENUMBER;
          instruction_bits[pc] |= BCODE_HAS_LINENUMBER;
        }
        }
    }
    }
 
 
  if (! verify_jvm_instructions_new (jcf, byte_ops, length))
  if (! verify_jvm_instructions_new (jcf, byte_ops, length))
    return;
    return;
 
 
  promote_arguments ();
  promote_arguments ();
  cache_this_class_ref (method);
  cache_this_class_ref (method);
  cache_cpool_data_ref ();
  cache_cpool_data_ref ();
 
 
  /* Translate bytecodes.  */
  /* Translate bytecodes.  */
  linenumber_pointer = linenumber_table;
  linenumber_pointer = linenumber_table;
  for (PC = 0; PC < length;)
  for (PC = 0; PC < length;)
    {
    {
      if ((instruction_bits [PC] & BCODE_TARGET) != 0 || PC == 0)
      if ((instruction_bits [PC] & BCODE_TARGET) != 0 || PC == 0)
        {
        {
          tree label = lookup_label (PC);
          tree label = lookup_label (PC);
          flush_quick_stack ();
          flush_quick_stack ();
          if ((instruction_bits [PC] & BCODE_TARGET) != 0)
          if ((instruction_bits [PC] & BCODE_TARGET) != 0)
            java_add_stmt (build1 (LABEL_EXPR, void_type_node, label));
            java_add_stmt (build1 (LABEL_EXPR, void_type_node, label));
          if ((instruction_bits[PC] & BCODE_VERIFIED) != 0)
          if ((instruction_bits[PC] & BCODE_VERIFIED) != 0)
            load_type_state (PC);
            load_type_state (PC);
        }
        }
 
 
      if (! (instruction_bits [PC] & BCODE_VERIFIED))
      if (! (instruction_bits [PC] & BCODE_VERIFIED))
        {
        {
          if (dead_code_index == -1)
          if (dead_code_index == -1)
            {
            {
              /* This is the start of a region of unreachable bytecodes.
              /* This is the start of a region of unreachable bytecodes.
                 They still need to be processed in order for EH ranges
                 They still need to be processed in order for EH ranges
                 to get handled correctly.  However, we can simply
                 to get handled correctly.  However, we can simply
                 replace these bytecodes with nops.  */
                 replace these bytecodes with nops.  */
              dead_code_index = PC;
              dead_code_index = PC;
            }
            }
 
 
          /* Turn this bytecode into a nop.  */
          /* Turn this bytecode into a nop.  */
          byte_ops[PC] = 0x0;
          byte_ops[PC] = 0x0;
        }
        }
       else
       else
        {
        {
          if (dead_code_index != -1)
          if (dead_code_index != -1)
            {
            {
              /* We've just reached the end of a region of dead code.  */
              /* We've just reached the end of a region of dead code.  */
              if (extra_warnings)
              if (extra_warnings)
                warning (0, "unreachable bytecode from %d to before %d",
                warning (0, "unreachable bytecode from %d to before %d",
                         dead_code_index, PC);
                         dead_code_index, PC);
              dead_code_index = -1;
              dead_code_index = -1;
            }
            }
        }
        }
 
 
      /* Handle possible line number entry for this PC.
      /* Handle possible line number entry for this PC.
 
 
         This code handles out-of-order and multiple linenumbers per PC,
         This code handles out-of-order and multiple linenumbers per PC,
         but is optimized for the case of line numbers increasing
         but is optimized for the case of line numbers increasing
         monotonically with PC. */
         monotonically with PC. */
      if ((instruction_bits[PC] & BCODE_HAS_LINENUMBER) != 0)
      if ((instruction_bits[PC] & BCODE_HAS_LINENUMBER) != 0)
        {
        {
          if ((instruction_bits[PC] & BCODE_HAS_MULTI_LINENUMBERS) != 0
          if ((instruction_bits[PC] & BCODE_HAS_MULTI_LINENUMBERS) != 0
              || GET_u2 (linenumber_pointer) != PC)
              || GET_u2 (linenumber_pointer) != PC)
            linenumber_pointer = linenumber_table;
            linenumber_pointer = linenumber_table;
          while (linenumber_pointer < linenumber_table + linenumber_count * 4)
          while (linenumber_pointer < linenumber_table + linenumber_count * 4)
            {
            {
              int pc = GET_u2 (linenumber_pointer);
              int pc = GET_u2 (linenumber_pointer);
              linenumber_pointer += 4;
              linenumber_pointer += 4;
              if (pc == PC)
              if (pc == PC)
                {
                {
                  int line = GET_u2 (linenumber_pointer - 2);
                  int line = GET_u2 (linenumber_pointer - 2);
                  input_location = linemap_line_start (line_table, line, 1);
                  input_location = linemap_line_start (line_table, line, 1);
                  if (input_location > max_location)
                  if (input_location > max_location)
                    max_location = input_location;
                    max_location = input_location;
                  if (!(instruction_bits[PC] & BCODE_HAS_MULTI_LINENUMBERS))
                  if (!(instruction_bits[PC] & BCODE_HAS_MULTI_LINENUMBERS))
                    break;
                    break;
                }
                }
            }
            }
        }
        }
      maybe_pushlevels (PC);
      maybe_pushlevels (PC);
      PC = process_jvm_instruction (PC, byte_ops, length);
      PC = process_jvm_instruction (PC, byte_ops, length);
      maybe_poplevels (PC);
      maybe_poplevels (PC);
    } /* for */
    } /* for */
 
 
  uncache_this_class_ref (method);
  uncache_this_class_ref (method);
 
 
  if (dead_code_index != -1)
  if (dead_code_index != -1)
    {
    {
      /* We've just reached the end of a region of dead code.  */
      /* We've just reached the end of a region of dead code.  */
      if (extra_warnings)
      if (extra_warnings)
        warning (0, "unreachable bytecode from %d to the end of the method",
        warning (0, "unreachable bytecode from %d to the end of the method",
                 dead_code_index);
                 dead_code_index);
    }
    }
 
 
  DECL_FUNCTION_LAST_LINE (method) = max_location;
  DECL_FUNCTION_LAST_LINE (method) = max_location;
}
}
 
 
static void
static void
java_push_constant_from_pool (JCF *jcf, int index)
java_push_constant_from_pool (JCF *jcf, int index)
{
{
  tree c;
  tree c;
  if (JPOOL_TAG (jcf, index) == CONSTANT_String)
  if (JPOOL_TAG (jcf, index) == CONSTANT_String)
    {
    {
      tree name;
      tree name;
      name = get_name_constant (jcf, JPOOL_USHORT1 (jcf, index));
      name = get_name_constant (jcf, JPOOL_USHORT1 (jcf, index));
      index = alloc_name_constant (CONSTANT_String, name);
      index = alloc_name_constant (CONSTANT_String, name);
      c = build_ref_from_constant_pool (index);
      c = build_ref_from_constant_pool (index);
      c = convert (promote_type (string_type_node), c);
      c = convert (promote_type (string_type_node), c);
    }
    }
  else if (JPOOL_TAG (jcf, index) == CONSTANT_Class
  else if (JPOOL_TAG (jcf, index) == CONSTANT_Class
           || JPOOL_TAG (jcf, index) == CONSTANT_ResolvedClass)
           || JPOOL_TAG (jcf, index) == CONSTANT_ResolvedClass)
    {
    {
      tree record = get_class_constant (jcf, index);
      tree record = get_class_constant (jcf, index);
      c = build_class_ref (record);
      c = build_class_ref (record);
    }
    }
  else
  else
    c = get_constant (jcf, index);
    c = get_constant (jcf, index);
  push_value (c);
  push_value (c);
}
}
 
 
int
int
process_jvm_instruction (int PC, const unsigned char* byte_ops,
process_jvm_instruction (int PC, const unsigned char* byte_ops,
                         long length ATTRIBUTE_UNUSED)
                         long length ATTRIBUTE_UNUSED)
{
{
  const char *opname; /* Temporary ??? */
  const char *opname; /* Temporary ??? */
  int oldpc = PC; /* PC at instruction start. */
  int oldpc = PC; /* PC at instruction start. */
 
 
  /* If the instruction is at the beginning of an exception handler,
  /* If the instruction is at the beginning of an exception handler,
     replace the top of the stack with the thrown object reference.  */
     replace the top of the stack with the thrown object reference.  */
  if (instruction_bits [PC] & BCODE_EXCEPTION_TARGET)
  if (instruction_bits [PC] & BCODE_EXCEPTION_TARGET)
    {
    {
      /* Note that the verifier will not emit a type map at all for
      /* Note that the verifier will not emit a type map at all for
         dead exception handlers.  In this case we just ignore the
         dead exception handlers.  In this case we just ignore the
         situation.  */
         situation.  */
      if ((instruction_bits[PC] & BCODE_VERIFIED) != 0)
      if ((instruction_bits[PC] & BCODE_VERIFIED) != 0)
        {
        {
          tree type = pop_type (promote_type (throwable_type_node));
          tree type = pop_type (promote_type (throwable_type_node));
          push_value (build_exception_object_ref (type));
          push_value (build_exception_object_ref (type));
        }
        }
    }
    }
 
 
  switch (byte_ops[PC++])
  switch (byte_ops[PC++])
    {
    {
#define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
#define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
    case OPCODE: \
    case OPCODE: \
      opname = #OPNAME; \
      opname = #OPNAME; \
      OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
      OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
      break;
      break;
 
 
#define RET(OPERAND_TYPE, OPERAND_VALUE)                                \
#define RET(OPERAND_TYPE, OPERAND_VALUE)                                \
  {                                                                     \
  {                                                                     \
    int saw_index = 0;                                                   \
    int saw_index = 0;                                                   \
    int index     = OPERAND_VALUE;                                      \
    int index     = OPERAND_VALUE;                                      \
    build_java_ret                                                      \
    build_java_ret                                                      \
      (find_local_variable (index, return_address_type_node, oldpc));   \
      (find_local_variable (index, return_address_type_node, oldpc));   \
  }
  }
 
 
#define JSR(OPERAND_TYPE, OPERAND_VALUE) \
#define JSR(OPERAND_TYPE, OPERAND_VALUE) \
  {                                                 \
  {                                                 \
    /* OPERAND_VALUE may have side-effects on PC */ \
    /* OPERAND_VALUE may have side-effects on PC */ \
    int opvalue = OPERAND_VALUE;                    \
    int opvalue = OPERAND_VALUE;                    \
    build_java_jsr (oldpc + opvalue, PC);           \
    build_java_jsr (oldpc + opvalue, PC);           \
  }
  }
 
 
/* Push a constant onto the stack. */
/* Push a constant onto the stack. */
#define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
#define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
  { int saw_index = 0;  int ival = (OPERAND_VALUE); \
  { int saw_index = 0;  int ival = (OPERAND_VALUE); \
    if (saw_index) java_push_constant_from_pool (current_jcf, ival); \
    if (saw_index) java_push_constant_from_pool (current_jcf, ival); \
    else expand_java_pushc (ival, OPERAND_TYPE##_type_node); }
    else expand_java_pushc (ival, OPERAND_TYPE##_type_node); }
 
 
/* internal macro added for use by the WIDE case */
/* internal macro added for use by the WIDE case */
#define LOAD_INTERNAL(OPTYPE, OPVALUE) \
#define LOAD_INTERNAL(OPTYPE, OPVALUE) \
  expand_load_internal (OPVALUE, type_map[OPVALUE], oldpc);
  expand_load_internal (OPVALUE, type_map[OPVALUE], oldpc);
 
 
/* Push local variable onto the opcode stack. */
/* Push local variable onto the opcode stack. */
#define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
#define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
  { \
  { \
    /* have to do this since OPERAND_VALUE may have side-effects */ \
    /* have to do this since OPERAND_VALUE may have side-effects */ \
    int opvalue = OPERAND_VALUE; \
    int opvalue = OPERAND_VALUE; \
    LOAD_INTERNAL(OPERAND_TYPE##_type_node, opvalue); \
    LOAD_INTERNAL(OPERAND_TYPE##_type_node, opvalue); \
  }
  }
 
 
#define RETURN(OPERAND_TYPE, OPERAND_VALUE) \
#define RETURN(OPERAND_TYPE, OPERAND_VALUE) \
  expand_java_return (OPERAND_TYPE##_type_node)
  expand_java_return (OPERAND_TYPE##_type_node)
 
 
#define REM_EXPR TRUNC_MOD_EXPR
#define REM_EXPR TRUNC_MOD_EXPR
#define BINOP(OPERAND_TYPE, OPERAND_VALUE) \
#define BINOP(OPERAND_TYPE, OPERAND_VALUE) \
  expand_java_binop (OPERAND_TYPE##_type_node, OPERAND_VALUE##_EXPR)
  expand_java_binop (OPERAND_TYPE##_type_node, OPERAND_VALUE##_EXPR)
 
 
#define FIELD(IS_STATIC, IS_PUT) \
#define FIELD(IS_STATIC, IS_PUT) \
  expand_java_field_op (IS_STATIC, IS_PUT, IMMEDIATE_u2)
  expand_java_field_op (IS_STATIC, IS_PUT, IMMEDIATE_u2)
 
 
#define TEST(OPERAND_TYPE, CONDITION) \
#define TEST(OPERAND_TYPE, CONDITION) \
  expand_test (CONDITION##_EXPR, OPERAND_TYPE##_type_node, oldpc+IMMEDIATE_s2)
  expand_test (CONDITION##_EXPR, OPERAND_TYPE##_type_node, oldpc+IMMEDIATE_s2)
 
 
#define COND(OPERAND_TYPE, CONDITION) \
#define COND(OPERAND_TYPE, CONDITION) \
  expand_cond (CONDITION##_EXPR, OPERAND_TYPE##_type_node, oldpc+IMMEDIATE_s2)
  expand_cond (CONDITION##_EXPR, OPERAND_TYPE##_type_node, oldpc+IMMEDIATE_s2)
 
 
#define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
#define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
  BRANCH_##OPERAND_TYPE (OPERAND_VALUE)
  BRANCH_##OPERAND_TYPE (OPERAND_VALUE)
 
 
#define BRANCH_GOTO(OPERAND_VALUE) \
#define BRANCH_GOTO(OPERAND_VALUE) \
  expand_java_goto (oldpc + OPERAND_VALUE)
  expand_java_goto (oldpc + OPERAND_VALUE)
 
 
#define BRANCH_CALL(OPERAND_VALUE) \
#define BRANCH_CALL(OPERAND_VALUE) \
  expand_java_call (oldpc + OPERAND_VALUE, oldpc)
  expand_java_call (oldpc + OPERAND_VALUE, oldpc)
 
 
#if 0
#if 0
#define BRANCH_RETURN(OPERAND_VALUE) \
#define BRANCH_RETURN(OPERAND_VALUE) \
  { \
  { \
    tree type = OPERAND_TYPE##_type_node; \
    tree type = OPERAND_TYPE##_type_node; \
    tree value = find_local_variable (OPERAND_VALUE, type, oldpc); \
    tree value = find_local_variable (OPERAND_VALUE, type, oldpc); \
    expand_java_ret (value); \
    expand_java_ret (value); \
  }
  }
#endif
#endif
 
 
#define NOT_IMPL(OPERAND_TYPE, OPERAND_VALUE) \
#define NOT_IMPL(OPERAND_TYPE, OPERAND_VALUE) \
          fprintf (stderr, "%3d: %s ", oldpc, opname); \
          fprintf (stderr, "%3d: %s ", oldpc, opname); \
          fprintf (stderr, "(not implemented)\n")
          fprintf (stderr, "(not implemented)\n")
#define NOT_IMPL1(OPERAND_VALUE) \
#define NOT_IMPL1(OPERAND_VALUE) \
          fprintf (stderr, "%3d: %s ", oldpc, opname); \
          fprintf (stderr, "%3d: %s ", oldpc, opname); \
          fprintf (stderr, "(not implemented)\n")
          fprintf (stderr, "(not implemented)\n")
 
 
#define BRANCH_RETURN(OPERAND_VALUE) NOT_IMPL1(OPERAND_VALUE)
#define BRANCH_RETURN(OPERAND_VALUE) NOT_IMPL1(OPERAND_VALUE)
 
 
#define STACK(SUBOP, COUNT) STACK_##SUBOP (COUNT)
#define STACK(SUBOP, COUNT) STACK_##SUBOP (COUNT)
 
 
#define STACK_POP(COUNT) java_stack_pop (COUNT)
#define STACK_POP(COUNT) java_stack_pop (COUNT)
 
 
#define STACK_SWAP(COUNT) java_stack_swap()
#define STACK_SWAP(COUNT) java_stack_swap()
 
 
#define STACK_DUP(COUNT) java_stack_dup (COUNT, 0)
#define STACK_DUP(COUNT) java_stack_dup (COUNT, 0)
#define STACK_DUPx1(COUNT) java_stack_dup (COUNT, 1)
#define STACK_DUPx1(COUNT) java_stack_dup (COUNT, 1)
#define STACK_DUPx2(COUNT) java_stack_dup (COUNT, 2)
#define STACK_DUPx2(COUNT) java_stack_dup (COUNT, 2)
 
 
#define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
#define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
  PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
  PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
 
 
#define LOOKUP_SWITCH \
#define LOOKUP_SWITCH \
  { jint default_offset = IMMEDIATE_s4;  jint npairs = IMMEDIATE_s4; \
  { jint default_offset = IMMEDIATE_s4;  jint npairs = IMMEDIATE_s4; \
    tree selector = pop_value (INT_type_node); \
    tree selector = pop_value (INT_type_node); \
    tree switch_expr = expand_java_switch (selector, oldpc + default_offset); \
    tree switch_expr = expand_java_switch (selector, oldpc + default_offset); \
    while (--npairs >= 0) \
    while (--npairs >= 0) \
      { \
      { \
        jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
        jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
        expand_java_add_case (switch_expr, match, oldpc + offset); \
        expand_java_add_case (switch_expr, match, oldpc + offset); \
      } \
      } \
  }
  }
 
 
#define TABLE_SWITCH \
#define TABLE_SWITCH \
  { jint default_offset = IMMEDIATE_s4; \
  { jint default_offset = IMMEDIATE_s4; \
    jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
    jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
    tree selector = pop_value (INT_type_node); \
    tree selector = pop_value (INT_type_node); \
    tree switch_expr = expand_java_switch (selector, oldpc + default_offset); \
    tree switch_expr = expand_java_switch (selector, oldpc + default_offset); \
    for (; low <= high; low++) \
    for (; low <= high; low++) \
      { \
      { \
        jint offset = IMMEDIATE_s4; \
        jint offset = IMMEDIATE_s4; \
        expand_java_add_case (switch_expr, low, oldpc + offset); \
        expand_java_add_case (switch_expr, low, oldpc + offset); \
      } \
      } \
  }
  }
 
 
#define INVOKE(MAYBE_STATIC, IS_INTERFACE) \
#define INVOKE(MAYBE_STATIC, IS_INTERFACE) \
  { int opcode = byte_ops[PC-1]; \
  { int opcode = byte_ops[PC-1]; \
    int method_ref_index = IMMEDIATE_u2; \
    int method_ref_index = IMMEDIATE_u2; \
    int nargs; \
    int nargs; \
    if (IS_INTERFACE) { nargs = IMMEDIATE_u1;  (void) IMMEDIATE_u1; } \
    if (IS_INTERFACE) { nargs = IMMEDIATE_u1;  (void) IMMEDIATE_u1; } \
    else nargs = -1; \
    else nargs = -1; \
    expand_invoke (opcode, method_ref_index, nargs); \
    expand_invoke (opcode, method_ref_index, nargs); \
  }
  }
 
 
/* Handle new, checkcast, instanceof */
/* Handle new, checkcast, instanceof */
#define OBJECT(TYPE, OP) \
#define OBJECT(TYPE, OP) \
  expand_java_##OP (get_class_constant (current_jcf, IMMEDIATE_u2))
  expand_java_##OP (get_class_constant (current_jcf, IMMEDIATE_u2))
 
 
#define ARRAY(OPERAND_TYPE, SUBOP) ARRAY_##SUBOP(OPERAND_TYPE)
#define ARRAY(OPERAND_TYPE, SUBOP) ARRAY_##SUBOP(OPERAND_TYPE)
 
 
#define ARRAY_LOAD(OPERAND_TYPE)                        \
#define ARRAY_LOAD(OPERAND_TYPE)                        \
  {                                                     \
  {                                                     \
    expand_java_arrayload( OPERAND_TYPE##_type_node );  \
    expand_java_arrayload( OPERAND_TYPE##_type_node );  \
  }
  }
 
 
#define ARRAY_STORE(OPERAND_TYPE)                       \
#define ARRAY_STORE(OPERAND_TYPE)                       \
  {                                                     \
  {                                                     \
    expand_java_arraystore( OPERAND_TYPE##_type_node ); \
    expand_java_arraystore( OPERAND_TYPE##_type_node ); \
  }
  }
 
 
#define ARRAY_LENGTH(OPERAND_TYPE) expand_java_array_length();
#define ARRAY_LENGTH(OPERAND_TYPE) expand_java_array_length();
#define ARRAY_NEW(OPERAND_TYPE) ARRAY_NEW_##OPERAND_TYPE()
#define ARRAY_NEW(OPERAND_TYPE) ARRAY_NEW_##OPERAND_TYPE()
#define ARRAY_NEW_PTR()                                                 \
#define ARRAY_NEW_PTR()                                                 \
    push_value (build_anewarray (get_class_constant (current_jcf,       \
    push_value (build_anewarray (get_class_constant (current_jcf,       \
                                                     IMMEDIATE_u2),     \
                                                     IMMEDIATE_u2),     \
                                 pop_value (int_type_node)));
                                 pop_value (int_type_node)));
#define ARRAY_NEW_NUM()                         \
#define ARRAY_NEW_NUM()                         \
  {                                             \
  {                                             \
    int atype = IMMEDIATE_u1;                   \
    int atype = IMMEDIATE_u1;                   \
    push_value (build_newarray (atype, pop_value (int_type_node)));\
    push_value (build_newarray (atype, pop_value (int_type_node)));\
  }
  }
#define ARRAY_NEW_MULTI()                                       \
#define ARRAY_NEW_MULTI()                                       \
  {                                                             \
  {                                                             \
    tree klass = get_class_constant (current_jcf, IMMEDIATE_u2 );       \
    tree klass = get_class_constant (current_jcf, IMMEDIATE_u2 );       \
    int  ndims = IMMEDIATE_u1;                                  \
    int  ndims = IMMEDIATE_u1;                                  \
    expand_java_multianewarray( klass, ndims );                 \
    expand_java_multianewarray( klass, ndims );                 \
  }
  }
 
 
#define UNOP(OPERAND_TYPE, OPERAND_VALUE) \
#define UNOP(OPERAND_TYPE, OPERAND_VALUE) \
  push_value (fold_build1 (NEGATE_EXPR, OPERAND_TYPE##_type_node, \
  push_value (fold_build1 (NEGATE_EXPR, OPERAND_TYPE##_type_node, \
                           pop_value (OPERAND_TYPE##_type_node)));
                           pop_value (OPERAND_TYPE##_type_node)));
 
 
#define CONVERT2(FROM_TYPE, TO_TYPE)                                     \
#define CONVERT2(FROM_TYPE, TO_TYPE)                                     \
  {                                                                      \
  {                                                                      \
    push_value (build1 (NOP_EXPR, int_type_node,                         \
    push_value (build1 (NOP_EXPR, int_type_node,                         \
                        (convert (TO_TYPE##_type_node,                   \
                        (convert (TO_TYPE##_type_node,                   \
                                  pop_value (FROM_TYPE##_type_node))))); \
                                  pop_value (FROM_TYPE##_type_node))))); \
  }
  }
 
 
#define CONVERT(FROM_TYPE, TO_TYPE)                             \
#define CONVERT(FROM_TYPE, TO_TYPE)                             \
  {                                                             \
  {                                                             \
    push_value (convert (TO_TYPE##_type_node,                   \
    push_value (convert (TO_TYPE##_type_node,                   \
                         pop_value (FROM_TYPE##_type_node)));   \
                         pop_value (FROM_TYPE##_type_node)));   \
  }
  }
 
 
/* internal macro added for use by the WIDE case
/* internal macro added for use by the WIDE case
   Added TREE_TYPE (decl) assignment, apbianco  */
   Added TREE_TYPE (decl) assignment, apbianco  */
#define STORE_INTERNAL(OPTYPE, OPVALUE)                         \
#define STORE_INTERNAL(OPTYPE, OPVALUE)                         \
  {                                                             \
  {                                                             \
    tree decl, value;                                           \
    tree decl, value;                                           \
    int index = OPVALUE;                                        \
    int index = OPVALUE;                                        \
    tree type = OPTYPE;                                         \
    tree type = OPTYPE;                                         \
    value = pop_value (type);                                   \
    value = pop_value (type);                                   \
    type = TREE_TYPE (value);                                   \
    type = TREE_TYPE (value);                                   \
    decl = find_local_variable (index, type, oldpc);            \
    decl = find_local_variable (index, type, oldpc);            \
    set_local_type (index, type);                               \
    set_local_type (index, type);                               \
    java_add_stmt (build2 (MODIFY_EXPR, type, decl, value));    \
    java_add_stmt (build2 (MODIFY_EXPR, type, decl, value));    \
  }
  }
 
 
#define STORE(OPERAND_TYPE, OPERAND_VALUE) \
#define STORE(OPERAND_TYPE, OPERAND_VALUE) \
  { \
  { \
    /* have to do this since OPERAND_VALUE may have side-effects */ \
    /* have to do this since OPERAND_VALUE may have side-effects */ \
    int opvalue = OPERAND_VALUE; \
    int opvalue = OPERAND_VALUE; \
    STORE_INTERNAL(OPERAND_TYPE##_type_node, opvalue); \
    STORE_INTERNAL(OPERAND_TYPE##_type_node, opvalue); \
  }
  }
 
 
#define SPECIAL(OPERAND_TYPE, INSTRUCTION) \
#define SPECIAL(OPERAND_TYPE, INSTRUCTION) \
  SPECIAL_##INSTRUCTION(OPERAND_TYPE)
  SPECIAL_##INSTRUCTION(OPERAND_TYPE)
 
 
#define SPECIAL_ENTER(IGNORED) MONITOR_OPERATION (soft_monitorenter_node)
#define SPECIAL_ENTER(IGNORED) MONITOR_OPERATION (soft_monitorenter_node)
#define SPECIAL_EXIT(IGNORED)  MONITOR_OPERATION (soft_monitorexit_node)
#define SPECIAL_EXIT(IGNORED)  MONITOR_OPERATION (soft_monitorexit_node)
 
 
#define MONITOR_OPERATION(call)                 \
#define MONITOR_OPERATION(call)                 \
  {                                             \
  {                                             \
    tree o = pop_value (ptr_type_node);         \
    tree o = pop_value (ptr_type_node);         \
    tree c;                                     \
    tree c;                                     \
    flush_quick_stack ();                       \
    flush_quick_stack ();                       \
    c = build_java_monitor (call, o);           \
    c = build_java_monitor (call, o);           \
    TREE_SIDE_EFFECTS (c) = 1;                  \
    TREE_SIDE_EFFECTS (c) = 1;                  \
    java_add_stmt (c);                          \
    java_add_stmt (c);                          \
  }
  }
 
 
#define SPECIAL_IINC(IGNORED) \
#define SPECIAL_IINC(IGNORED) \
  { \
  { \
    unsigned int local_var_index = IMMEDIATE_u1; \
    unsigned int local_var_index = IMMEDIATE_u1; \
    int ival = IMMEDIATE_s1; \
    int ival = IMMEDIATE_s1; \
    expand_iinc(local_var_index, ival, oldpc); \
    expand_iinc(local_var_index, ival, oldpc); \
  }
  }
 
 
#define SPECIAL_WIDE(IGNORED) \
#define SPECIAL_WIDE(IGNORED) \
  { \
  { \
    int modified_opcode = IMMEDIATE_u1; \
    int modified_opcode = IMMEDIATE_u1; \
    unsigned int local_var_index = IMMEDIATE_u2; \
    unsigned int local_var_index = IMMEDIATE_u2; \
    switch (modified_opcode) \
    switch (modified_opcode) \
      { \
      { \
      case OPCODE_iinc: \
      case OPCODE_iinc: \
        { \
        { \
          int ival = IMMEDIATE_s2; \
          int ival = IMMEDIATE_s2; \
          expand_iinc (local_var_index, ival, oldpc); \
          expand_iinc (local_var_index, ival, oldpc); \
          break; \
          break; \
        } \
        } \
      case OPCODE_iload: \
      case OPCODE_iload: \
      case OPCODE_lload: \
      case OPCODE_lload: \
      case OPCODE_fload: \
      case OPCODE_fload: \
      case OPCODE_dload: \
      case OPCODE_dload: \
      case OPCODE_aload: \
      case OPCODE_aload: \
        { \
        { \
          /* duplicate code from LOAD macro */ \
          /* duplicate code from LOAD macro */ \
          LOAD_INTERNAL(operand_type[modified_opcode], local_var_index); \
          LOAD_INTERNAL(operand_type[modified_opcode], local_var_index); \
          break; \
          break; \
        } \
        } \
      case OPCODE_istore: \
      case OPCODE_istore: \
      case OPCODE_lstore: \
      case OPCODE_lstore: \
      case OPCODE_fstore: \
      case OPCODE_fstore: \
      case OPCODE_dstore: \
      case OPCODE_dstore: \
      case OPCODE_astore: \
      case OPCODE_astore: \
        { \
        { \
          STORE_INTERNAL(operand_type[modified_opcode], local_var_index); \
          STORE_INTERNAL(operand_type[modified_opcode], local_var_index); \
          break; \
          break; \
        } \
        } \
      default: \
      default: \
        error ("unrecogized wide sub-instruction"); \
        error ("unrecogized wide sub-instruction"); \
      } \
      } \
  }
  }
 
 
#define SPECIAL_THROW(IGNORED) \
#define SPECIAL_THROW(IGNORED) \
  build_java_athrow (pop_value (throwable_type_node))
  build_java_athrow (pop_value (throwable_type_node))
 
 
#define SPECIAL_BREAK NOT_IMPL1
#define SPECIAL_BREAK NOT_IMPL1
#define IMPL          NOT_IMPL
#define IMPL          NOT_IMPL
 
 
#include "javaop.def"
#include "javaop.def"
#undef JAVAOP
#undef JAVAOP
   default:
   default:
    fprintf (stderr, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);
    fprintf (stderr, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);
  }
  }
  return PC;
  return PC;
}
}
 
 
/* Return the opcode at PC in the code section pointed to by
/* Return the opcode at PC in the code section pointed to by
   CODE_OFFSET.  */
   CODE_OFFSET.  */
 
 
static unsigned char
static unsigned char
peek_opcode_at_pc (JCF *jcf, int code_offset, int pc)
peek_opcode_at_pc (JCF *jcf, int code_offset, int pc)
{
{
  unsigned char opcode;
  unsigned char opcode;
  long absolute_offset = (long)JCF_TELL (jcf);
  long absolute_offset = (long)JCF_TELL (jcf);
 
 
  JCF_SEEK (jcf, code_offset);
  JCF_SEEK (jcf, code_offset);
  opcode = jcf->read_ptr [pc];
  opcode = jcf->read_ptr [pc];
  JCF_SEEK (jcf, absolute_offset);
  JCF_SEEK (jcf, absolute_offset);
  return opcode;
  return opcode;
}
}
 
 
/* Some bytecode compilers are emitting accurate LocalVariableTable
/* Some bytecode compilers are emitting accurate LocalVariableTable
   attributes. Here's an example:
   attributes. Here's an example:
 
 
     PC   <t>store_<n>
     PC   <t>store_<n>
     PC+1 ...
     PC+1 ...
 
 
     Attribute "LocalVariableTable"
     Attribute "LocalVariableTable"
     slot #<n>: ... (PC: PC+1 length: L)
     slot #<n>: ... (PC: PC+1 length: L)
 
 
   This is accurate because the local in slot <n> really exists after
   This is accurate because the local in slot <n> really exists after
   the opcode at PC is executed, hence from PC+1 to PC+1+L.
   the opcode at PC is executed, hence from PC+1 to PC+1+L.
 
 
   This procedure recognizes this situation and extends the live range
   This procedure recognizes this situation and extends the live range
   of the local in SLOT to START_PC-1 or START_PC-2 (depending on the
   of the local in SLOT to START_PC-1 or START_PC-2 (depending on the
   length of the store instruction.)
   length of the store instruction.)
 
 
   This function is used by `give_name_to_locals' so that a local's
   This function is used by `give_name_to_locals' so that a local's
   DECL features a DECL_LOCAL_START_PC such that the first related
   DECL features a DECL_LOCAL_START_PC such that the first related
   store operation will use DECL as a destination, not an unrelated
   store operation will use DECL as a destination, not an unrelated
   temporary created for the occasion.
   temporary created for the occasion.
 
 
   This function uses a global (instruction_bits) `note_instructions' should
   This function uses a global (instruction_bits) `note_instructions' should
   have allocated and filled properly.  */
   have allocated and filled properly.  */
 
 
int
int
maybe_adjust_start_pc (struct JCF *jcf, int code_offset,
maybe_adjust_start_pc (struct JCF *jcf, int code_offset,
                       int start_pc, int slot)
                       int start_pc, int slot)
{
{
  int first, index, opcode;
  int first, index, opcode;
  int pc, insn_pc;
  int pc, insn_pc;
  int wide_found = 0;
  int wide_found = 0;
 
 
  if (!start_pc)
  if (!start_pc)
    return start_pc;
    return start_pc;
 
 
  first = index = -1;
  first = index = -1;
 
 
  /* Find last previous instruction and remember it */
  /* Find last previous instruction and remember it */
  for (pc = start_pc-1; pc; pc--)
  for (pc = start_pc-1; pc; pc--)
    if (instruction_bits [pc] & BCODE_INSTRUCTION_START)
    if (instruction_bits [pc] & BCODE_INSTRUCTION_START)
      break;
      break;
  insn_pc = pc;
  insn_pc = pc;
 
 
  /* Retrieve the instruction, handle `wide'. */
  /* Retrieve the instruction, handle `wide'. */
  opcode = (int) peek_opcode_at_pc (jcf, code_offset, pc++);
  opcode = (int) peek_opcode_at_pc (jcf, code_offset, pc++);
  if (opcode == OPCODE_wide)
  if (opcode == OPCODE_wide)
    {
    {
      wide_found = 1;
      wide_found = 1;
      opcode = (int) peek_opcode_at_pc (jcf, code_offset, pc++);
      opcode = (int) peek_opcode_at_pc (jcf, code_offset, pc++);
    }
    }
 
 
  switch (opcode)
  switch (opcode)
    {
    {
    case OPCODE_astore_0:
    case OPCODE_astore_0:
    case OPCODE_astore_1:
    case OPCODE_astore_1:
    case OPCODE_astore_2:
    case OPCODE_astore_2:
    case OPCODE_astore_3:
    case OPCODE_astore_3:
      first = OPCODE_astore_0;
      first = OPCODE_astore_0;
      break;
      break;
 
 
    case OPCODE_istore_0:
    case OPCODE_istore_0:
    case OPCODE_istore_1:
    case OPCODE_istore_1:
    case OPCODE_istore_2:
    case OPCODE_istore_2:
    case OPCODE_istore_3:
    case OPCODE_istore_3:
      first = OPCODE_istore_0;
      first = OPCODE_istore_0;
      break;
      break;
 
 
    case OPCODE_lstore_0:
    case OPCODE_lstore_0:
    case OPCODE_lstore_1:
    case OPCODE_lstore_1:
    case OPCODE_lstore_2:
    case OPCODE_lstore_2:
    case OPCODE_lstore_3:
    case OPCODE_lstore_3:
      first = OPCODE_lstore_0;
      first = OPCODE_lstore_0;
      break;
      break;
 
 
    case OPCODE_fstore_0:
    case OPCODE_fstore_0:
    case OPCODE_fstore_1:
    case OPCODE_fstore_1:
    case OPCODE_fstore_2:
    case OPCODE_fstore_2:
    case OPCODE_fstore_3:
    case OPCODE_fstore_3:
      first = OPCODE_fstore_0;
      first = OPCODE_fstore_0;
      break;
      break;
 
 
    case OPCODE_dstore_0:
    case OPCODE_dstore_0:
    case OPCODE_dstore_1:
    case OPCODE_dstore_1:
    case OPCODE_dstore_2:
    case OPCODE_dstore_2:
    case OPCODE_dstore_3:
    case OPCODE_dstore_3:
      first = OPCODE_dstore_0;
      first = OPCODE_dstore_0;
      break;
      break;
 
 
    case OPCODE_astore:
    case OPCODE_astore:
    case OPCODE_istore:
    case OPCODE_istore:
    case OPCODE_lstore:
    case OPCODE_lstore:
    case OPCODE_fstore:
    case OPCODE_fstore:
    case OPCODE_dstore:
    case OPCODE_dstore:
      index = peek_opcode_at_pc (jcf, code_offset, pc);
      index = peek_opcode_at_pc (jcf, code_offset, pc);
      if (wide_found)
      if (wide_found)
        {
        {
          int other = peek_opcode_at_pc (jcf, code_offset, ++pc);
          int other = peek_opcode_at_pc (jcf, code_offset, ++pc);
          index = (other << 8) + index;
          index = (other << 8) + index;
        }
        }
      break;
      break;
    }
    }
 
 
  /* Now we decide: first >0 means we have a <t>store_<n>, index >0
  /* Now we decide: first >0 means we have a <t>store_<n>, index >0
     means we have a <t>store. */
     means we have a <t>store. */
  if ((first > 0 && opcode - first == slot) || (index > 0 && index == slot))
  if ((first > 0 && opcode - first == slot) || (index > 0 && index == slot))
    start_pc = insn_pc;
    start_pc = insn_pc;
 
 
  return start_pc;
  return start_pc;
}
}
 
 
/* Force the (direct) sub-operands of NODE to be evaluated in left-to-right
/* Force the (direct) sub-operands of NODE to be evaluated in left-to-right
   order, as specified by Java Language Specification.
   order, as specified by Java Language Specification.
 
 
   The problem is that while expand_expr will evaluate its sub-operands in
   The problem is that while expand_expr will evaluate its sub-operands in
   left-to-right order, for variables it will just return an rtx (i.e.
   left-to-right order, for variables it will just return an rtx (i.e.
   an lvalue) for the variable (rather than an rvalue).  So it is possible
   an lvalue) for the variable (rather than an rvalue).  So it is possible
   that a later sub-operand will change the register, and when the
   that a later sub-operand will change the register, and when the
   actual operation is done, it will use the new value, when it should
   actual operation is done, it will use the new value, when it should
   have used the original value.
   have used the original value.
 
 
   We fix this by using save_expr.  This forces the sub-operand to be
   We fix this by using save_expr.  This forces the sub-operand to be
   copied into a fresh virtual register,
   copied into a fresh virtual register,
 
 
   For method invocation, we modify the arguments so that a
   For method invocation, we modify the arguments so that a
   left-to-right order evaluation is performed. Saved expressions
   left-to-right order evaluation is performed. Saved expressions
   will, in CALL_EXPR order, be reused when the call will be expanded.
   will, in CALL_EXPR order, be reused when the call will be expanded.
 
 
   We also promote outgoing args if needed.  */
   We also promote outgoing args if needed.  */
 
 
tree
tree
force_evaluation_order (tree node)
force_evaluation_order (tree node)
{
{
  if (flag_syntax_only)
  if (flag_syntax_only)
    return node;
    return node;
  if (TREE_CODE (node) == CALL_EXPR
  if (TREE_CODE (node) == CALL_EXPR
      || (TREE_CODE (node) == COMPOUND_EXPR
      || (TREE_CODE (node) == COMPOUND_EXPR
          && TREE_CODE (TREE_OPERAND (node, 0)) == CALL_EXPR
          && TREE_CODE (TREE_OPERAND (node, 0)) == CALL_EXPR
          && TREE_CODE (TREE_OPERAND (node, 1)) == SAVE_EXPR))
          && TREE_CODE (TREE_OPERAND (node, 1)) == SAVE_EXPR))
    {
    {
      tree call, cmp;
      tree call, cmp;
      int i, nargs;
      int i, nargs;
 
 
      /* Account for wrapped around ctors.  */
      /* Account for wrapped around ctors.  */
      if (TREE_CODE (node) == COMPOUND_EXPR)
      if (TREE_CODE (node) == COMPOUND_EXPR)
        call = TREE_OPERAND (node, 0);
        call = TREE_OPERAND (node, 0);
      else
      else
        call = node;
        call = node;
 
 
      nargs = call_expr_nargs (call);
      nargs = call_expr_nargs (call);
 
 
      /* This reverses the evaluation order. This is a desired effect. */
      /* This reverses the evaluation order. This is a desired effect. */
      for (i = 0, cmp = NULL_TREE; i < nargs; i++)
      for (i = 0, cmp = NULL_TREE; i < nargs; i++)
        {
        {
          tree arg = CALL_EXPR_ARG (call, i);
          tree arg = CALL_EXPR_ARG (call, i);
          /* Promote types smaller than integer.  This is required by
          /* Promote types smaller than integer.  This is required by
             some ABIs.  */
             some ABIs.  */
          tree type = TREE_TYPE (arg);
          tree type = TREE_TYPE (arg);
          tree saved;
          tree saved;
          if (targetm.calls.promote_prototypes (type)
          if (targetm.calls.promote_prototypes (type)
              && INTEGRAL_TYPE_P (type)
              && INTEGRAL_TYPE_P (type)
              && INT_CST_LT_UNSIGNED (TYPE_SIZE (type),
              && INT_CST_LT_UNSIGNED (TYPE_SIZE (type),
                                      TYPE_SIZE (integer_type_node)))
                                      TYPE_SIZE (integer_type_node)))
            arg = fold_convert (integer_type_node, arg);
            arg = fold_convert (integer_type_node, arg);
 
 
          saved = save_expr (force_evaluation_order (arg));
          saved = save_expr (force_evaluation_order (arg));
          cmp = (cmp == NULL_TREE ? saved :
          cmp = (cmp == NULL_TREE ? saved :
                 build2 (COMPOUND_EXPR, void_type_node, cmp, saved));
                 build2 (COMPOUND_EXPR, void_type_node, cmp, saved));
 
 
          CALL_EXPR_ARG (call, i) = saved;
          CALL_EXPR_ARG (call, i) = saved;
        }
        }
 
 
      if (cmp && TREE_CODE (cmp) == COMPOUND_EXPR)
      if (cmp && TREE_CODE (cmp) == COMPOUND_EXPR)
        TREE_SIDE_EFFECTS (cmp) = 1;
        TREE_SIDE_EFFECTS (cmp) = 1;
 
 
      if (cmp)
      if (cmp)
        {
        {
          cmp = build2 (COMPOUND_EXPR, TREE_TYPE (node), cmp, node);
          cmp = build2 (COMPOUND_EXPR, TREE_TYPE (node), cmp, node);
          if (TREE_TYPE (cmp) != void_type_node)
          if (TREE_TYPE (cmp) != void_type_node)
            cmp = save_expr (cmp);
            cmp = save_expr (cmp);
          TREE_SIDE_EFFECTS (cmp) = 1;
          TREE_SIDE_EFFECTS (cmp) = 1;
          node = cmp;
          node = cmp;
        }
        }
    }
    }
  return node;
  return node;
}
}
 
 
/* Build a node to represent empty statements and blocks. */
/* Build a node to represent empty statements and blocks. */
 
 
tree
tree
build_java_empty_stmt (void)
build_java_empty_stmt (void)
{
{
  tree t = build_empty_stmt (input_location);
  tree t = build_empty_stmt (input_location);
  return t;
  return t;
}
}
 
 
/* Promote all args of integral type before generating any code.  */
/* Promote all args of integral type before generating any code.  */
 
 
static void
static void
promote_arguments (void)
promote_arguments (void)
{
{
  int i;
  int i;
  tree arg;
  tree arg;
  for (arg = DECL_ARGUMENTS (current_function_decl), i = 0;
  for (arg = DECL_ARGUMENTS (current_function_decl), i = 0;
       arg != NULL_TREE;  arg = TREE_CHAIN (arg), i++)
       arg != NULL_TREE;  arg = TREE_CHAIN (arg), i++)
    {
    {
      tree arg_type = TREE_TYPE (arg);
      tree arg_type = TREE_TYPE (arg);
      if (INTEGRAL_TYPE_P (arg_type)
      if (INTEGRAL_TYPE_P (arg_type)
          && TYPE_PRECISION (arg_type) < 32)
          && TYPE_PRECISION (arg_type) < 32)
        {
        {
          tree copy = find_local_variable (i, integer_type_node, -1);
          tree copy = find_local_variable (i, integer_type_node, -1);
          java_add_stmt (build2 (MODIFY_EXPR, integer_type_node,
          java_add_stmt (build2 (MODIFY_EXPR, integer_type_node,
                                 copy,
                                 copy,
                                 fold_convert (integer_type_node, arg)));
                                 fold_convert (integer_type_node, arg)));
        }
        }
      if (TYPE_IS_WIDE (arg_type))
      if (TYPE_IS_WIDE (arg_type))
        i++;
        i++;
    }
    }
}
}
 
 
/* Create a local variable that points to the constant pool.  */
/* Create a local variable that points to the constant pool.  */
 
 
static void
static void
cache_cpool_data_ref (void)
cache_cpool_data_ref (void)
{
{
  if (optimize)
  if (optimize)
    {
    {
      tree cpool;
      tree cpool;
      tree d = build_constant_data_ref (flag_indirect_classes);
      tree d = build_constant_data_ref (flag_indirect_classes);
      tree cpool_ptr = build_decl (input_location, VAR_DECL, NULL_TREE,
      tree cpool_ptr = build_decl (input_location, VAR_DECL, NULL_TREE,
                                   build_pointer_type (TREE_TYPE (d)));
                                   build_pointer_type (TREE_TYPE (d)));
      java_add_local_var (cpool_ptr);
      java_add_local_var (cpool_ptr);
      TREE_CONSTANT (cpool_ptr) = 1;
      TREE_CONSTANT (cpool_ptr) = 1;
 
 
      java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (cpool_ptr),
      java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (cpool_ptr),
                             cpool_ptr, build_address_of (d)));
                             cpool_ptr, build_address_of (d)));
      cpool = build1 (INDIRECT_REF, TREE_TYPE (d), cpool_ptr);
      cpool = build1 (INDIRECT_REF, TREE_TYPE (d), cpool_ptr);
      TREE_THIS_NOTRAP (cpool) = 1;
      TREE_THIS_NOTRAP (cpool) = 1;
      TYPE_CPOOL_DATA_REF (output_class) = cpool;
      TYPE_CPOOL_DATA_REF (output_class) = cpool;
    }
    }
}
}
 
 
#include "gt-java-expr.h"
#include "gt-java-expr.h"
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.