text: /* Process declarations and variables for the GNU compiler for the
     Java(TM) language.
     Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
     Free Software Foundation, Inc.
  
  This file is part of GNU CC.
  
  GNU CC is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2, or (at your option)
  any later version.
  
  GNU CC is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
  
  You should have received a copy of the GNU General Public License
  along with GNU CC; see the file COPYING.  If not, write to
  the Free Software Foundation, 59 Temple Place - Suite 330,
  Boston, MA 02111-1307, USA.
  
  Java and all Java-based marks are trademarks or registered trademarks
  of Sun Microsystems, Inc. in the United States and other countries.
  The Free Software Foundation is independent of Sun Microsystems, Inc.  */
  
  /* Hacked by Per Bothner <bothner@cygnus.com> February 1996. */
  
  #include "config.h"
  #include "system.h"
  #include "tree.h"
  #include "rtl.h"
  #include "toplev.h"
  #include "flags.h"
  #include "java-tree.h"
  #include "jcf.h"
  #include "function.h"
  #include "expr.h"
  #include "libfuncs.h"
  #include "except.h"
  #include "java-except.h"
  #include "ggc.h"
  
  #if defined (DEBUG_JAVA_BINDING_LEVELS)
  extern void indent PROTO((void));
  #endif
  
  static tree push_jvm_slot PARAMS ((int, tree));
  static tree lookup_name_current_level PARAMS ((tree));
  static tree push_promoted_type PARAMS ((const char *, tree));
  static struct binding_level *make_binding_level PARAMS ((void));
  static tree create_primitive_vtable PARAMS ((const char *));
  static tree check_local_named_variable PARAMS ((tree, tree, int, int *));
  static tree check_local_unnamed_variable PARAMS ((tree, tree, tree));
  
  /* Set to non-zero value in order to emit class initilization code
     before static field references.  */
  extern int always_initialize_class_p;
  
  /* The DECL_MAP is a mapping from (index, type) to a decl node.
     If index < max_locals, it is the index of a local variable.
     if index >= max_locals, then index-max_locals is a stack slot.
     The DECL_MAP mapping is represented as a TREE_VEC whose elements
     are a list of decls (VAR_DECL or PARM_DECL) chained by
     DECL_LOCAL_SLOT_CHAIN; the index finds the TREE_VEC element, and then
     we search the chain for a decl with a matching TREE_TYPE. */
  
  tree decl_map;
  
  /* A list of local variables VAR_DECLs for this method that we have seen
     debug information, but we have not reached their starting (byte) PC yet. */
  
  static tree pending_local_decls = NULL_TREE;
  
  /* Push a local variable or stack slot into the decl_map,
     and assign it an rtl. */
  
  #if defined(DEBUG_JAVA_BINDING_LEVELS)
  int binding_depth = 0;
  int is_class_level = 0;
  int current_pc;
  
  void
  indent ()
  {
    register unsigned i;
  
    for (i = 0; i < binding_depth*2; i++)
      putc (' ', stderr);
  }
  #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
  
  static tree
  push_jvm_slot (index, decl)
       int index;
       tree decl;
  {
    struct rtx_def *rtl = NULL;
    tree type = TREE_TYPE (decl);
    tree tmp;
  
    DECL_CONTEXT (decl) = current_function_decl;
    layout_decl (decl, 0);
  
    /* See if we have an appropriate rtl (i.e. same mode) at this index.
       If so, we must use it. */ 
    tmp = TREE_VEC_ELT (decl_map, index);
    while (tmp != NULL_TREE)
      {
        if (TYPE_MODE (type) == TYPE_MODE (TREE_TYPE (tmp)))
  	rtl = DECL_RTL_IF_SET (tmp);
        if (rtl != NULL)
  	break;
       tmp = DECL_LOCAL_SLOT_CHAIN (tmp);
      }
    if (rtl != NULL)
      SET_DECL_RTL (decl, rtl);
    else
      {
        if (index >= DECL_MAX_LOCALS (current_function_decl))
  	DECL_REGISTER (decl) = 1;
        expand_decl (decl);
      }
  
    /* Now link the decl into the decl_map. */
    if (DECL_LANG_SPECIFIC (decl) == NULL)
      {
        MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
        DECL_LOCAL_START_PC (decl) = 0;
        DECL_LOCAL_END_PC (decl) = DECL_CODE_LENGTH (current_function_decl);
        DECL_LOCAL_SLOT_NUMBER (decl) = index;
      }
    DECL_LOCAL_SLOT_CHAIN (decl) = TREE_VEC_ELT (decl_map, index);
    TREE_VEC_ELT (decl_map, index) = decl;
    return decl;
  }
  
  /* Find out if 'decl' passed in fits the defined PC location better than
     'best'.  Return decl if it does, return best if it doesn't.  If decl
     is returned, then updated is set to true.  */
  
  static tree
  check_local_named_variable (best, decl, pc, updated)
       tree best;
       tree decl;
       int pc;
       int *updated;
  {
    if (pc >= DECL_LOCAL_START_PC (decl)
        && pc < DECL_LOCAL_END_PC (decl))
      {
        if (best == NULL_TREE
  	  || (DECL_LOCAL_START_PC (decl) > DECL_LOCAL_START_PC (best)
  	      && DECL_LOCAL_END_PC (decl) < DECL_LOCAL_END_PC (best)))
          {
  	  *updated = 1;
  	  return decl;
  	}
      }
    
    return best;
  }
  
  /* Find the best declaration based upon type.  If 'decl' fits 'type' better
     than 'best', return 'decl'.  Otherwise return 'best'.  */
  
  static tree
  check_local_unnamed_variable (best, decl, type)
       tree best;
       tree decl;
       tree type;
  {
      if (TREE_TYPE (decl) == type
  	|| (TREE_CODE (TREE_TYPE (decl)) == TREE_CODE (type)
  	    && TYPE_PRECISION (TREE_TYPE (decl)) <= 32
  	    && TYPE_PRECISION (type) <= 32
  	    && TREE_CODE (type) != POINTER_TYPE)
  	|| (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE
  	    && type == ptr_type_node))
        {
  	if (best == NULL_TREE
  	    || (TREE_TYPE (decl) == type && TREE_TYPE (best) != type))
  	  return decl;
        }
  
      return best;
  }
  
  
  /* Find a VAR_DECL (or PARM_DECL) at local index INDEX that has type TYPE,
     that is valid at PC (or -1 if any pc).
     If there is no existing matching decl, allocate one.  */
  
  tree
  find_local_variable (index, type, pc)
       int index;
       tree type;
       int pc;
  {
    tree decl = TREE_VEC_ELT (decl_map, index);
    tree best = NULL_TREE;
    int found_scoped_var = 0;
  
    /* Scan through every declaration that has been created in this slot. */
    while (decl != NULL_TREE)
      {
         /* Variables created in give_name_to_locals() have a name and have
   	 a specified scope, so we can handle them specifically.  We want
   	 to use the specific decls created for those so they are assigned
   	 the right variables in the debugging information. */
        if (DECL_NAME (decl) != NULL_TREE)
  	{
  	  /* This is a variable we have a name for, so it has a scope
  	     supplied in the class file.  But it only matters when we
  	     actually have a PC to use.  If pc<0, then we are asking
  	     for a stack slot and this decl won't be one of those. */
   	  if (pc >= 0)
   	    best = check_local_named_variable (best, decl, pc,
   					       &found_scoped_var);
   	}
        /* We scan for type information unless we found a variable in the
  	 proper scope already. */
        else if (!found_scoped_var)
   	{
   	  /* If we don't have scoping information for a variable, we use
   	     a different method to look it up. */
   	  best = check_local_unnamed_variable (best, decl, type);
   	}
  
        decl = DECL_LOCAL_SLOT_CHAIN (decl);
      }
  
    if (best != NULL_TREE)
      return best;
  
    /* If we don't find a match, create one with the type passed in. */
    return push_jvm_slot (index, build_decl (VAR_DECL, NULL_TREE, type));
  }
  
  
  /* Same as find_local_index, except that INDEX is a stack index. */
  
  tree
  find_stack_slot (index, type)
       int index;
       tree type;
  {
    return find_local_variable (index + DECL_MAX_LOCALS (current_function_decl),
  			      type, -1);
  }
  
  struct binding_level
    {
      /* A chain of _DECL nodes for all variables, constants, functions,
       * and typedef types.  These are in the reverse of the order supplied.
       */
      tree names;
  
      /* For each level, a list of shadowed outer-level local definitions
         to be restored when this level is popped.
         Each link is a TREE_LIST whose TREE_PURPOSE is an identifier and
         whose TREE_VALUE is its old definition (a kind of ..._DECL node).  */
      tree shadowed;
  
      /* For each level (except not the global one),
         a chain of BLOCK nodes for all the levels
         that were entered and exited one level down.  */
      tree blocks;
  
      /* The BLOCK node for this level, if one has been preallocated.
         If 0, the BLOCK is allocated (if needed) when the level is popped.  */
      tree this_block;
  
      /* The binding level which this one is contained in (inherits from).  */
      struct binding_level *level_chain;
  
      /* The bytecode PC that marks the end of this level. */
      int end_pc;
      /* The bytecode PC that marks the start of this level. */
      int start_pc;
  
  #if defined(DEBUG_JAVA_BINDING_LEVELS)
      /* Binding depth at which this level began.  */
      unsigned binding_depth;
  #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
    };
  
  #define NULL_BINDING_LEVEL (struct binding_level *) NULL
  
  /* The binding level currently in effect.  */
  
  static struct binding_level *current_binding_level;
  
  /* A chain of binding_level structures awaiting reuse.  */
  
  static struct binding_level *free_binding_level;
  
  /* The outermost binding level, for names of file scope.
     This is created when the compiler is started and exists
     through the entire run.  */
  
  static struct binding_level *global_binding_level;
  
  /* A PC value bigger than any PC value we may ever may encounter. */
  
  #define LARGEST_PC (( (unsigned int)1 << (HOST_BITS_PER_INT - 1)) - 1)
  
  /* Binding level structures are initialized by copying this one.  */
  
  static struct binding_level clear_binding_level
    = {NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE,
         NULL_BINDING_LEVEL, LARGEST_PC, 0};
  
  #if 0
  /* A list (chain of TREE_LIST nodes) of all LABEL_DECLs in the function
     that have names.  Here so we can clear out their names' definitions
     at the end of the function.  */
  
  static tree named_labels;
  
  /* A list of LABEL_DECLs from outer contexts that are currently shadowed.  */
  
  static tree shadowed_labels;
  #endif
  
  int flag_traditional;
  
  tree java_global_trees[JTI_MAX];
    
  /* Build (and pushdecl) a "promoted type" for all standard
     types shorter than int.  */
  
  static tree
  push_promoted_type (name, actual_type)
       const char *name;
       tree actual_type;
  {
    tree type = make_node (TREE_CODE (actual_type));
  #if 1
    tree in_min = TYPE_MIN_VALUE (int_type_node);
    tree in_max = TYPE_MAX_VALUE (int_type_node);
  #else
    tree in_min = TYPE_MIN_VALUE (actual_type);
    tree in_max = TYPE_MAX_VALUE (actual_type);
  #endif
    TYPE_MIN_VALUE (type) = copy_node (in_min);
    TREE_TYPE (TYPE_MIN_VALUE (type)) = type;
    TYPE_MAX_VALUE (type) = copy_node (in_max);
    TREE_TYPE (TYPE_MAX_VALUE (type)) = type;
    TYPE_PRECISION (type) = TYPE_PRECISION (int_type_node);
    layout_type (type);
    pushdecl (build_decl (TYPE_DECL, get_identifier (name), type));
    return type;
  }
  
  /* Return a definition for a builtin function named NAME and whose data type
     is TYPE.  TYPE should be a function type with argument types.
     FUNCTION_CODE tells later passes how to compile calls to this function.
     See tree.h for its possible values.
  
     If LIBRARY_NAME is nonzero, use that for DECL_ASSEMBLER_NAME,
     the name to be called if we can't opencode the function.  */
  
  tree
  builtin_function (name, type, function_code, class, library_name)
       const char *name;
       tree type;
       int function_code;
       enum built_in_class class;
       const char *library_name;
  {
    tree decl = build_decl (FUNCTION_DECL, get_identifier (name), type);
    DECL_EXTERNAL (decl) = 1;
    TREE_PUBLIC (decl) = 1;
    if (library_name)
      SET_DECL_ASSEMBLER_NAME (decl, get_identifier (library_name));
    make_decl_rtl (decl, NULL);
    pushdecl (decl);
    DECL_BUILT_IN_CLASS (decl) = class;
    DECL_FUNCTION_CODE (decl) = function_code;
    return decl;
  }
  
  /* Return tree that represents a vtable for a primitive array.  */
  static tree
  create_primitive_vtable (name)
       const char *name;
  {
    tree r;
    char buf[50];
  
    sprintf (buf, "_Jv_%sVTable", name);
    r = build_decl (VAR_DECL, get_identifier (buf), ptr_type_node);
    DECL_EXTERNAL (r) = 1;
    return r;
  }
  
  void
  java_init_decl_processing ()
  {
    register tree endlink;
    tree field = NULL_TREE;
    tree t;
  
    init_class_processing ();
  
    current_function_decl = NULL;
    current_binding_level = NULL_BINDING_LEVEL;
    free_binding_level = NULL_BINDING_LEVEL;
    pushlevel (0);	/* make the binding_level structure for global names */
    global_binding_level = current_binding_level;
  
    /* The code here must be similar to build_common_tree_nodes{,_2} in
       tree.c, especially as to the order of initializing common nodes.  */
    error_mark_node = make_node (ERROR_MARK);
    TREE_TYPE (error_mark_node) = error_mark_node;
  
    /* Create sizetype first - needed for other types. */
    initialize_sizetypes ();
  
    byte_type_node = make_signed_type (8);
    pushdecl (build_decl (TYPE_DECL, get_identifier ("byte"), byte_type_node));
    short_type_node = make_signed_type (16);
    pushdecl (build_decl (TYPE_DECL, get_identifier ("short"), short_type_node));
    int_type_node = make_signed_type (32);
    pushdecl (build_decl (TYPE_DECL, get_identifier ("int"), int_type_node));
    long_type_node = make_signed_type (64);
    pushdecl (build_decl (TYPE_DECL, get_identifier ("long"), long_type_node));
  
    unsigned_byte_type_node = make_unsigned_type (8);
    pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned byte"),
  			unsigned_byte_type_node));
    unsigned_short_type_node = make_unsigned_type (16);
    pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned short"),
  			unsigned_short_type_node));
    unsigned_int_type_node = make_unsigned_type (32);
    pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned int"),
  			unsigned_int_type_node));
    unsigned_long_type_node = make_unsigned_type (64);
    pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned long"),
  			unsigned_long_type_node));
  
    set_sizetype (make_unsigned_type (POINTER_SIZE));
  
    /* Define these next since types below may used them.  */
    integer_type_node = type_for_size (INT_TYPE_SIZE, 0);
    integer_zero_node = build_int_2 (0, 0);
    integer_one_node = build_int_2 (1, 0);
    integer_two_node = build_int_2 (2, 0);
    integer_four_node = build_int_2 (4, 0);
    integer_minus_one_node = build_int_2 (-1, -1);
  
    size_zero_node = size_int (0);
    size_one_node = size_int (1);
    bitsize_zero_node = bitsize_int (0);
    bitsize_one_node = bitsize_int (1);
    bitsize_unit_node = bitsize_int (BITS_PER_UNIT);
  
    long_zero_node = build_int_2 (0, 0);
    TREE_TYPE (long_zero_node) = long_type_node;
  
    void_type_node = make_node (VOID_TYPE);
    pushdecl (build_decl (TYPE_DECL, get_identifier ("void"), void_type_node));
    layout_type (void_type_node);	/* Uses size_zero_node */
    ptr_type_node = build_pointer_type (void_type_node);
    t = make_node (VOID_TYPE);
    layout_type (t); /* Uses size_zero_node */
    return_address_type_node = build_pointer_type (t);
  
    null_pointer_node = build_int_2 (0, 0);
    TREE_TYPE (null_pointer_node) = ptr_type_node;
  
    /* Used by the parser to represent empty statements and blocks. */
    empty_stmt_node = build1 (NOP_EXPR, void_type_node, size_zero_node);
    CAN_COMPLETE_NORMALLY (empty_stmt_node) = 1;
  
  #if 0
    /* Make a type to be the domain of a few array types
       whose domains don't really matter.
       200 is small enough that it always fits in size_t
       and large enough that it can hold most function names for the
       initializations of __FUNCTION__ and __PRETTY_FUNCTION__.  */
    short_array_type_node = build_prim_array_type (short_type_node, 200);
  #endif
    char_type_node = make_node (CHAR_TYPE);
    TYPE_PRECISION (char_type_node) = 16;
    fixup_unsigned_type (char_type_node);
    pushdecl (build_decl (TYPE_DECL, get_identifier ("char"), char_type_node));
  
    boolean_type_node = make_node (BOOLEAN_TYPE);
    TYPE_PRECISION (boolean_type_node) = 1;
    fixup_unsigned_type (boolean_type_node);
    pushdecl (build_decl (TYPE_DECL, get_identifier ("boolean"),
  			boolean_type_node));
    boolean_false_node = TYPE_MIN_VALUE (boolean_type_node);
    boolean_true_node = TYPE_MAX_VALUE (boolean_type_node);
  
    promoted_byte_type_node
      = push_promoted_type ("promoted_byte", byte_type_node);
    promoted_short_type_node
      = push_promoted_type ("promoted_short", short_type_node);
    promoted_char_type_node
      = push_promoted_type ("promoted_char", char_type_node);
    promoted_boolean_type_node
      = push_promoted_type ("promoted_boolean", boolean_type_node);
  
    float_type_node = make_node (REAL_TYPE);
    TYPE_PRECISION (float_type_node) = 32;
    pushdecl (build_decl (TYPE_DECL, get_identifier ("float"),
                          float_type_node));
    layout_type (float_type_node);
  
    double_type_node = make_node (REAL_TYPE);
    TYPE_PRECISION (double_type_node) = 64;
    pushdecl (build_decl (TYPE_DECL, get_identifier ("double"),
                          double_type_node));
    layout_type (double_type_node);
  
    float_zero_node = build_real (float_type_node, dconst0);
    double_zero_node = build_real (double_type_node, dconst0);
  
    /* These are the vtables for arrays of primitives.  */
    boolean_array_vtable = create_primitive_vtable ("boolean");
    byte_array_vtable = create_primitive_vtable ("byte");
    char_array_vtable = create_primitive_vtable ("char");
    short_array_vtable = create_primitive_vtable ("short");
    int_array_vtable = create_primitive_vtable ("int");
    long_array_vtable = create_primitive_vtable ("long");
    float_array_vtable = create_primitive_vtable ("float");
    double_array_vtable = create_primitive_vtable ("double");
  
    /* As you're adding items here, please update the code right after
       this section, so that the filename containing the source code of
       the pre-defined class gets registered correctly. */
    unqualified_object_id_node = get_identifier ("Object");
    object_type_node = lookup_class (get_identifier ("java.lang.Object"));
    object_ptr_type_node = promote_type (object_type_node);
    string_type_node = lookup_class (get_identifier ("java.lang.String"));
    string_ptr_type_node = promote_type (string_type_node);
    class_type_node = lookup_class (get_identifier ("java.lang.Class"));
    throwable_type_node = lookup_class (get_identifier ("java.lang.Throwable"));
    exception_type_node = lookup_class (get_identifier ("java.lang.Exception"));
    runtime_exception_type_node = 
      lookup_class (get_identifier ("java.lang.RuntimeException"));
    error_exception_type_node = 
      lookup_class (get_identifier ("java.lang.Error"));
    class_not_found_type_node = 
      lookup_class (get_identifier ("java.lang.ClassNotFoundException"));
    no_class_def_found_type_node = 
      lookup_class (get_identifier ("java.lang.NoClassDefFoundError"));
  
    rawdata_ptr_type_node
      = promote_type (lookup_class (get_identifier ("gnu.gcj.RawData")));
  
    add_predefined_file (get_identifier ("java/lang/Class.java"));
    add_predefined_file (get_identifier ("java/lang/Error.java"));
    add_predefined_file (get_identifier ("java/lang/Object.java"));
    add_predefined_file (get_identifier ("java/lang/RuntimeException.java"));
    add_predefined_file (get_identifier ("java/lang/String.java"));
    add_predefined_file (get_identifier ("java/lang/Throwable.java"));
    add_predefined_file (get_identifier ("gnu/gcj/RawData.java"));
    add_predefined_file (get_identifier ("java/lang/Exception.java"));
    add_predefined_file (get_identifier ("java/lang/ClassNotFoundException.java"));
    add_predefined_file (get_identifier ("java/lang/NoClassDefFoundError.java"));
    add_predefined_file (get_identifier ("gnu/gcj/RawData.java"));
  
    methodtable_type = make_node (RECORD_TYPE);
    layout_type (methodtable_type);
    build_decl (TYPE_DECL, get_identifier ("methodtable"), methodtable_type);
    methodtable_ptr_type = build_pointer_type (methodtable_type);
  
    TYPE_identifier_node = get_identifier ("TYPE");
    init_identifier_node = get_identifier ("<init>");
    clinit_identifier_node = get_identifier ("<clinit>");
    finit_identifier_node = get_identifier ("finit$");
    instinit_identifier_node = get_identifier ("instinit$");
    void_signature_node = get_identifier ("()V");
    length_identifier_node = get_identifier ("length");
    finalize_identifier_node = get_identifier ("finalize");
    this_identifier_node = get_identifier ("this");
    super_identifier_node = get_identifier ("super");
    continue_identifier_node = get_identifier ("continue");
    access0_identifier_node = get_identifier ("access$0");
    classdollar_identifier_node = get_identifier ("class$");
  
    /* for lack of a better place to put this stub call */
    init_expr_processing();
  
    utf8const_type = make_node (RECORD_TYPE);
    PUSH_FIELD (utf8const_type, field, "hash", unsigned_short_type_node);
    PUSH_FIELD (utf8const_type, field, "length", unsigned_short_type_node);
    FINISH_RECORD (utf8const_type);
    utf8const_ptr_type = build_pointer_type (utf8const_type);
  
    constants_type_node = make_node (RECORD_TYPE);
    PUSH_FIELD (constants_type_node, field, "size", unsigned_int_type_node);
    PUSH_FIELD (constants_type_node, field, "tags", ptr_type_node);
    PUSH_FIELD (constants_type_node, field, "data", ptr_type_node);
    FINISH_RECORD (constants_type_node);
    build_decl (TYPE_DECL, get_identifier ("constants"), constants_type_node);
  
    access_flags_type_node = unsigned_short_type_node;
  
    dtable_type = make_node (RECORD_TYPE);
    dtable_ptr_type = build_pointer_type (dtable_type);
  
    one_elt_array_domain_type = build_index_type (integer_one_node);
    otable_type = build_array_type (integer_type_node, 
  				  one_elt_array_domain_type);
    otable_ptr_type = build_pointer_type (otable_type);
  
    method_symbol_type = make_node (RECORD_TYPE);
    PUSH_FIELD (method_symbol_type, field, "clname", utf8const_ptr_type);
    PUSH_FIELD (method_symbol_type, field, "name", utf8const_ptr_type);
    PUSH_FIELD (method_symbol_type, field, "signature", utf8const_ptr_type);
    FINISH_RECORD (method_symbol_type);
  
    method_symbols_array_type = build_array_type (method_symbol_type, 
  						one_elt_array_domain_type);
    method_symbols_array_ptr_type = build_pointer_type 
  				  (method_symbols_array_type);
  
    otable_decl = build_decl (VAR_DECL, get_identifier ("otable"), otable_type);
    DECL_EXTERNAL (otable_decl) = 1;
    TREE_STATIC (otable_decl) = 1;
    TREE_READONLY (otable_decl) = 1;
    pushdecl (otable_decl);
    
    otable_syms_decl = build_decl (VAR_DECL, get_identifier ("otable_syms"), 
      method_symbols_array_type);
    TREE_STATIC (otable_syms_decl) = 1;
    TREE_CONSTANT (otable_syms_decl) = 1;
    pushdecl (otable_syms_decl);
    
    PUSH_FIELD (object_type_node, field, "vtable", dtable_ptr_type);
    /* This isn't exactly true, but it is what we have in the source.
       There is an unresolved issue here, which is whether the vtable
       should be marked by the GC.  */
    if (! flag_hash_synchronization)
      PUSH_FIELD (object_type_node, field, "sync_info",
  		build_pointer_type (object_type_node));
    for (t = TYPE_FIELDS (object_type_node); t != NULL_TREE; t = TREE_CHAIN (t))
      FIELD_PRIVATE (t) = 1;
    FINISH_RECORD (object_type_node);
  
    field_type_node = make_node (RECORD_TYPE);
    field_ptr_type_node = build_pointer_type (field_type_node);
    method_type_node = make_node (RECORD_TYPE);
    method_ptr_type_node = build_pointer_type (method_type_node);
  
    set_super_info (0, class_type_node, object_type_node, 0);
    set_super_info (0, string_type_node, object_type_node, 0);
    class_ptr_type = build_pointer_type (class_type_node);
  
    PUSH_FIELD (class_type_node, field, "next", class_ptr_type);
    PUSH_FIELD (class_type_node, field, "name", utf8const_ptr_type);
    PUSH_FIELD (class_type_node, field, "accflags", access_flags_type_node);
    PUSH_FIELD (class_type_node, field, "superclass", class_ptr_type);
    PUSH_FIELD (class_type_node, field, "constants", constants_type_node);
    PUSH_FIELD (class_type_node, field, "methods", method_ptr_type_node);
    PUSH_FIELD (class_type_node, field, "method_count", short_type_node);
    PUSH_FIELD (class_type_node, field, "vtable_method_count", short_type_node);
    PUSH_FIELD (class_type_node, field, "fields", field_ptr_type_node);
    PUSH_FIELD (class_type_node, field, "size_in_bytes", int_type_node);
    PUSH_FIELD (class_type_node, field, "field_count", short_type_node);
    PUSH_FIELD (class_type_node, field, "static_field_count", short_type_node);
    PUSH_FIELD (class_type_node, field, "vtable", dtable_ptr_type);
    PUSH_FIELD (class_type_node, field, "otable", otable_ptr_type);
    PUSH_FIELD (class_type_node, field, "otable_syms", 
    	      method_symbols_array_ptr_type);
    PUSH_FIELD (class_type_node, field, "interfaces",
  	      build_pointer_type (class_ptr_type));
    PUSH_FIELD (class_type_node, field, "loader", ptr_type_node);
    PUSH_FIELD (class_type_node, field, "interface_count", short_type_node);
    PUSH_FIELD (class_type_node, field, "state", byte_type_node);
    PUSH_FIELD (class_type_node, field, "thread", ptr_type_node);
    PUSH_FIELD (class_type_node, field, "depth", short_type_node);
    PUSH_FIELD (class_type_node, field, "ancestors", ptr_type_node);
    PUSH_FIELD (class_type_node, field, "idt", ptr_type_node);  
    PUSH_FIELD (class_type_node, field, "arrayclass", ptr_type_node);  
    PUSH_FIELD (class_type_node, field, "protectionDomain", ptr_type_node);
    for (t = TYPE_FIELDS (class_type_node);  t != NULL_TREE;  t = TREE_CHAIN (t))
      FIELD_PRIVATE (t) = 1;
    push_super_field (class_type_node, object_type_node);
  
    FINISH_RECORD (class_type_node);
    build_decl (TYPE_DECL, get_identifier ("Class"), class_type_node);
  
    field_info_union_node = make_node (UNION_TYPE);
    PUSH_FIELD (field_info_union_node, field, "boffset", int_type_node);
    PUSH_FIELD (field_info_union_node, field, "addr", ptr_type_node);
  #if 0
    PUSH_FIELD (field_info_union_node, field, "idx", unsigned_short_type_node);
  #endif
    layout_type (field_info_union_node);
  
    PUSH_FIELD (field_type_node, field, "name", utf8const_ptr_type);
    PUSH_FIELD (field_type_node, field, "type", class_ptr_type);
    PUSH_FIELD (field_type_node, field, "accflags", access_flags_type_node);
    PUSH_FIELD (field_type_node, field, "bsize", unsigned_short_type_node);
    PUSH_FIELD (field_type_node, field, "info", field_info_union_node);
    FINISH_RECORD (field_type_node);
    build_decl (TYPE_DECL, get_identifier ("Field"), field_type_node);
  
    nativecode_ptr_array_type_node
      = build_array_type (nativecode_ptr_type_node, one_elt_array_domain_type);
  
    PUSH_FIELD (dtable_type, field, "class", class_ptr_type);
    PUSH_FIELD (dtable_type, field, "methods", nativecode_ptr_array_type_node);
    FINISH_RECORD (dtable_type);
    build_decl (TYPE_DECL, get_identifier ("dispatchTable"), dtable_type);
  
  #define jint_type int_type_node
  #define jint_ptr_type ptr_type_node
  
    jexception_type = make_node (RECORD_TYPE);
    PUSH_FIELD (jexception_type, field, "start_pc", ptr_type_node);
    PUSH_FIELD (jexception_type, field, "end_pc", ptr_type_node);
    PUSH_FIELD (jexception_type, field, "handler_pc", ptr_type_node);
    PUSH_FIELD (jexception_type, field, "catch_type", class_ptr_type);
    FINISH_RECORD (jexception_type);
    build_decl (TYPE_DECL, get_identifier ("jexception"), field_type_node);
    jexception_ptr_type = build_pointer_type (jexception_type);
  
    lineNumberEntry_type = make_node (RECORD_TYPE);
    PUSH_FIELD (lineNumberEntry_type, field, "line_nr", unsigned_short_type_node);
    PUSH_FIELD (lineNumberEntry_type, field, "start_pc", ptr_type_node);
    FINISH_RECORD (lineNumberEntry_type);
  
    lineNumbers_type = make_node (RECORD_TYPE);
    PUSH_FIELD (lineNumbers_type, field, "length", unsigned_int_type_node);
    FINISH_RECORD (lineNumbers_type);
  
  #define instn_ptr_type_node ptr_type_node	/* XXX JH */
  
  #define lineNumbers_ptr_type_node build_pointer_type(lineNumbers_type)
  
    PUSH_FIELD (method_type_node, field, "name", utf8const_ptr_type);
    PUSH_FIELD (method_type_node, field, "signature", utf8const_ptr_type);
    PUSH_FIELD (method_type_node, field, "accflags", access_flags_type_node);
    PUSH_FIELD (method_type_node, field, "index", unsigned_short_type_node);
    PUSH_FIELD (method_type_node, field, "ncode", nativecode_ptr_type_node);
    PUSH_FIELD (method_type_node, field, "throws", ptr_type_node);
    FINISH_RECORD (method_type_node);
    build_decl (TYPE_DECL, get_identifier ("Method"), method_type_node);
  
    endlink = end_params_node = tree_cons (NULL_TREE, void_type_node, NULL_TREE);
  
    t = tree_cons (NULL_TREE, class_ptr_type,
  		 tree_cons (NULL_TREE, int_type_node, endlink));
    alloc_object_node = builtin_function ("_Jv_AllocObject",
  					build_function_type (ptr_type_node, t),
  					0, NOT_BUILT_IN, NULL);
    DECL_IS_MALLOC (alloc_object_node) = 1;
    alloc_no_finalizer_node = 
      builtin_function ("_Jv_AllocObjectNoFinalizer",
  		      build_function_type (ptr_type_node, t),
  		      0, NOT_BUILT_IN, NULL);
    DECL_IS_MALLOC (alloc_no_finalizer_node) = 1;
  
    t = tree_cons (NULL_TREE, ptr_type_node, endlink);
    soft_initclass_node = builtin_function ("_Jv_InitClass",
  					  build_function_type (void_type_node,
  							       t),
  					  0, NOT_BUILT_IN, NULL);
  
    throw_node = builtin_function ("_Jv_Throw",
  				 build_function_type (ptr_type_node, t),
  				 0, NOT_BUILT_IN, NULL);
    /* Mark throw_nodes as `noreturn' functions with side effects.  */
    TREE_THIS_VOLATILE (throw_node) = 1;
    TREE_SIDE_EFFECTS (throw_node) = 1;
  
    t = build_function_type (int_type_node, endlink);
    soft_monitorenter_node 
      = builtin_function ("_Jv_MonitorEnter", t, 0, NOT_BUILT_IN, NULL);
    soft_monitorexit_node 
      = builtin_function ("_Jv_MonitorExit", t, 0, NOT_BUILT_IN, NULL);
    
    t = tree_cons (NULL_TREE, int_type_node, 
  		 tree_cons (NULL_TREE, int_type_node, endlink));
    soft_newarray_node
        = builtin_function ("_Jv_NewPrimArray",
  			  build_function_type(ptr_type_node, t),
  			  0, NOT_BUILT_IN, NULL);
    DECL_IS_MALLOC (soft_newarray_node) = 1;
  
    t = tree_cons (NULL_TREE, int_type_node,
  		 tree_cons (NULL_TREE, class_ptr_type,
  			    tree_cons (NULL_TREE, object_ptr_type_node, endlink)));
    soft_anewarray_node
        = builtin_function ("_Jv_NewObjectArray",
  			  build_function_type (ptr_type_node, t),
  			  0, NOT_BUILT_IN, NULL);
    DECL_IS_MALLOC (soft_anewarray_node) = 1;
  
    t = tree_cons (NULL_TREE, ptr_type_node,
  		 tree_cons (NULL_TREE, int_type_node, endlink));
    soft_multianewarray_node
        = builtin_function ("_Jv_NewMultiArray",
  			  build_function_type (ptr_type_node, t),
  			  0, NOT_BUILT_IN, NULL);
    DECL_IS_MALLOC (soft_multianewarray_node) = 1;
  
    t = build_function_type (void_type_node, 
  			   tree_cons (NULL_TREE, int_type_node, endlink));
    soft_badarrayindex_node
        = builtin_function ("_Jv_ThrowBadArrayIndex", t, 
  			  0, NOT_BUILT_IN, NULL);
    /* Mark soft_badarrayindex_node as a `noreturn' function with side
       effects.  */
    TREE_THIS_VOLATILE (soft_badarrayindex_node) = 1;
    TREE_SIDE_EFFECTS (soft_badarrayindex_node) = 1;
  
    soft_nullpointer_node
      = builtin_function ("_Jv_ThrowNullPointerException",
  			build_function_type (void_type_node, endlink),
  			0, NOT_BUILT_IN, NULL);
    /* Mark soft_nullpointer_node as a `noreturn' function with side
       effects.  */
    TREE_THIS_VOLATILE (soft_nullpointer_node) = 1;
    TREE_SIDE_EFFECTS (soft_nullpointer_node) = 1;
  
    t = tree_cons (NULL_TREE, class_ptr_type,
  		 tree_cons (NULL_TREE, object_ptr_type_node, endlink));
    soft_checkcast_node
      = builtin_function ("_Jv_CheckCast",
  			build_function_type (ptr_type_node, t),
  			0, NOT_BUILT_IN, NULL);
    t = tree_cons (NULL_TREE, object_ptr_type_node,
  		 tree_cons (NULL_TREE, class_ptr_type, endlink));
    soft_instanceof_node
      = builtin_function ("_Jv_IsInstanceOf",
  			build_function_type (boolean_type_node, t),
  			0, NOT_BUILT_IN, NULL);
    t = tree_cons (NULL_TREE, object_ptr_type_node,
  		 tree_cons (NULL_TREE, object_ptr_type_node, endlink));
    soft_checkarraystore_node
      = builtin_function ("_Jv_CheckArrayStore",
  			build_function_type (void_type_node, t),
  			0, NOT_BUILT_IN, NULL);
    t = tree_cons (NULL_TREE, ptr_type_node,
  		 tree_cons (NULL_TREE, ptr_type_node,
  			    tree_cons (NULL_TREE, int_type_node, endlink)));
    soft_lookupinterfacemethod_node 
      = builtin_function ("_Jv_LookupInterfaceMethodIdx",
  			build_function_type (ptr_type_node, t),
  			0, NOT_BUILT_IN, NULL);
  
    t = tree_cons (NULL_TREE, object_ptr_type_node,
  		 tree_cons (NULL_TREE, ptr_type_node,
  			    tree_cons (NULL_TREE, ptr_type_node, endlink)));
    soft_lookupjnimethod_node
      = builtin_function ("_Jv_LookupJNIMethod",
  			build_function_type (ptr_type_node, t),
  			0, NOT_BUILT_IN, NULL);
    t = tree_cons (NULL_TREE, ptr_type_node, endlink);
    soft_getjnienvnewframe_node
      = builtin_function ("_Jv_GetJNIEnvNewFrame",
  			build_function_type (ptr_type_node, t),
  			0, NOT_BUILT_IN, NULL);
    soft_jnipopsystemframe_node
      = builtin_function ("_Jv_JNI_PopSystemFrame",
  			build_function_type (ptr_type_node, t),
  			0, NOT_BUILT_IN, NULL);
  
    t = tree_cons (NULL_TREE, double_type_node,
  		 tree_cons (NULL_TREE, double_type_node, endlink));
    soft_fmod_node
      = builtin_function ("__builtin_fmod",
  			build_function_type (double_type_node, t),
  			BUILT_IN_FMOD, BUILT_IN_NORMAL, "fmod");
  
  #if 0
    t = tree_cons (NULL_TREE, float_type_node,
  		 tree_cons (NULL_TREE, float_type_node, endlink));
    soft_fmodf_node
      = builtin_function ("__builtin_fmodf",
  			build_function_type (float_type_node, t),
  			BUILT_IN_FMOD, BUILT_IN_NORMAL, "fmodf");
  #endif
      
    soft_idiv_node
      = builtin_function ("_Jv_divI",
  			build_function_type (int_type_node, t),
  			0, NOT_BUILT_IN, NULL);
  
    soft_irem_node
      = builtin_function ("_Jv_remI",
  			build_function_type (int_type_node, t),
  			0, NOT_BUILT_IN, NULL);
  
    soft_ldiv_node
      = builtin_function ("_Jv_divJ",
  			build_function_type (long_type_node, t),
  			0, NOT_BUILT_IN, NULL);
  
    soft_lrem_node
      = builtin_function ("_Jv_remJ",
  			build_function_type (long_type_node, t),
  			0, NOT_BUILT_IN, NULL);
  
    /* Initialize variables for except.c.  */
    eh_personality_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS
                                               ? "__gcj_personality_sj0"
                                               : "__gcj_personality_v0");
    lang_eh_runtime_type = prepare_eh_table_type;
  
    init_jcf_parse ();
  
    /* Register nodes with the garbage collector.  */
    ggc_add_tree_root (java_global_trees, 
  		     sizeof (java_global_trees) / sizeof (tree));
    ggc_add_tree_root (&decl_map, 1);
    ggc_add_tree_root (&pending_local_decls, 1);
  
    initialize_builtins ();
  }
  
  
  /* Look up NAME in the current binding level and its superiors
     in the namespace of variables, functions and typedefs.
     Return a ..._DECL node of some kind representing its definition,
     or return 0 if it is undefined.  */
  
  tree
  lookup_name (name)
       tree name;
  {
    register tree val;
    if (current_binding_level != global_binding_level
        && IDENTIFIER_LOCAL_VALUE (name))
      val = IDENTIFIER_LOCAL_VALUE (name);
    else
      val = IDENTIFIER_GLOBAL_VALUE (name);
    return val;
  }
  
  /* Similar to `lookup_name' but look only at current binding level and
     the previous one if its the parameter level.  */
  
  static tree
  lookup_name_current_level (name)
       tree name;
  {
    register tree t;
  
    if (current_binding_level == global_binding_level)
      return IDENTIFIER_GLOBAL_VALUE (name);
  
    if (IDENTIFIER_LOCAL_VALUE (name) == 0)
      return 0;
  
    for (t = current_binding_level->names; t; t = TREE_CHAIN (t))
      if (DECL_NAME (t) == name)
        break;
  
    return t;
  }
  
  /* Use a binding level to record a labeled block declaration */
  
  void
  push_labeled_block (lb)
      tree lb;
  {
    register tree name = DECL_NAME (LABELED_BLOCK_LABEL (lb));
    register struct binding_level *b = current_binding_level;
    tree oldlocal = IDENTIFIER_LOCAL_VALUE (name);
    if (oldlocal != 0)
        b->shadowed = tree_cons (name, oldlocal, b->shadowed);
    TREE_CHAIN (lb) = b->names;
    b->names = lb;
    IDENTIFIER_LOCAL_VALUE (name) = lb;
  }
  
  /* Pop the current binding level, reinstalling values for the previous
     labeled block */
  
  void
  pop_labeled_block ()
  {
    struct binding_level *b = current_binding_level;
    tree label =  b->names;
    IDENTIFIER_LOCAL_VALUE (DECL_NAME (LABELED_BLOCK_LABEL (label))) = 
      NULL_TREE;
    if (b->shadowed)
      IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (b->shadowed)) = 
        TREE_VALUE (b->shadowed);
  
    /* Pop the current level, and free the structure for reuse.  */
    current_binding_level = current_binding_level->level_chain;
    b->level_chain = free_binding_level;
    free_binding_level = b;
  }
  
  /* Record a decl-node X as belonging to the current lexical scope.
     Check for errors (such as an incompatible declaration for the same
     name already seen in the same scope).
  
     Returns either X or an old decl for the same name.
     If an old decl is returned, it may have been smashed
     to agree with what X says.  */
  
  tree
  pushdecl (x)
       tree x;
  {
    register tree t;
    register tree name = DECL_NAME (x);
    register struct binding_level *b = current_binding_level;
    
    if (TREE_CODE (x) != TYPE_DECL)
      DECL_CONTEXT (x) = current_function_decl;
    if (name)
      {
        const char *file;
        int line;
  
        t = lookup_name_current_level (name);
        if (t != 0 && t == error_mark_node)
  	/* error_mark_node is 0 for a while during initialization!  */
  	{
  	  t = 0;
  	  error_with_decl (x, "`%s' used prior to declaration");
  	}
  
        if (t != 0)
  	{
  	  file = DECL_SOURCE_FILE (t);
  	  line = DECL_SOURCE_LINE (t);
  	}
  
        /* If we're naming a hitherto-unnamed type, set its TYPE_NAME
  	 to point to the TYPE_DECL.
  	 Since Java does not have typedefs, a type can only have
  	 one (true) name, given by a class, interface, or builtin. */
        if (TREE_CODE (x) == TYPE_DECL
  	  && TYPE_NAME (TREE_TYPE (x)) == 0
  	  && TREE_TYPE (x) != error_mark_node)
  	{
  	  TYPE_NAME (TREE_TYPE (x)) = x;
  	  TYPE_STUB_DECL (TREE_TYPE (x)) = x;
  	}
  
        /* This name is new in its binding level.
  	 Install the new declaration and return it.  */
        if (b == global_binding_level)
  	{
  	  /* Install a global value.  */
  	  
  	  IDENTIFIER_GLOBAL_VALUE (name) = x;
  	}
        else
  	{
  	  /* Here to install a non-global value.  */
  	  tree oldlocal = IDENTIFIER_LOCAL_VALUE (name);
  	  IDENTIFIER_LOCAL_VALUE (name) = x;
  
  #if 0
  	  /* Warn if shadowing an argument at the top level of the body.  */
  	  if (oldlocal != 0 && !DECL_EXTERNAL (x)
  	      /* This warning doesn't apply to the parms of a nested fcn.  */
  	      && ! current_binding_level->parm_flag
  	      /* Check that this is one level down from the parms.  */
  	      && current_binding_level->level_chain->parm_flag
  	      /* Check that the decl being shadowed
  		 comes from the parm level, one level up.  */
  	      && chain_member (oldlocal, current_binding_level->level_chain->names))
  	    {
  	      if (TREE_CODE (oldlocal) == PARM_DECL)
  		pedwarn ("declaration of `%s' shadows a parameter",
  			 IDENTIFIER_POINTER (name));
  	      else
  		pedwarn ("declaration of `%s' shadows a symbol from the parameter list",
  			 IDENTIFIER_POINTER (name));
  	    }
  
  	  /* Maybe warn if shadowing something else.  */
  	  else if (warn_shadow && !DECL_EXTERNAL (x)
  		   /* No shadow warnings for internally generated vars.  */
  		   && DECL_SOURCE_LINE (x) != 0
  		   /* No shadow warnings for vars made for inlining.  */
  		   && ! DECL_FROM_INLINE (x))
  	    {
  	      const char *warnstring = 0;
  
  	      if (TREE_CODE (x) == PARM_DECL
  		  && current_binding_level->level_chain->parm_flag)
  		/* Don't warn about the parm names in function declarator
  		   within a function declarator.
  		   It would be nice to avoid warning in any function
  		   declarator in a declaration, as opposed to a definition,
  		   but there is no way to tell it's not a definition.  */
  		;
  	      else if (oldlocal != 0 && TREE_CODE (oldlocal) == PARM_DECL)
  		warnstring = "declaration of `%s' shadows a parameter";
  	      else if (oldlocal != 0)
  		warnstring = "declaration of `%s' shadows previous local";
  	      else if (IDENTIFIER_GLOBAL_VALUE (name) != 0
  		       && IDENTIFIER_GLOBAL_VALUE (name) != error_mark_node)
  		warnstring = "declaration of `%s' shadows global declaration";
  
  	      if (warnstring)
  		warning (warnstring, IDENTIFIER_POINTER (name));
  	    }
  #endif
  
  	  /* If storing a local value, there may already be one (inherited).
  	     If so, record it for restoration when this binding level ends.  */
  	  if (oldlocal != 0)
  	    b->shadowed = tree_cons (name, oldlocal, b->shadowed);
  	}
      }
  
    /* Put decls on list in reverse order.
       We will reverse them later if necessary.  */
    TREE_CHAIN (x) = b->names;
    b->names = x;
  
    return x;
  }
  
  void
  pushdecl_force_head (x)
       tree x;
  {
    current_binding_level->names = x;
  }
  
  /* Like pushdecl, only it places X in GLOBAL_BINDING_LEVEL, if appropriate.  */
  
  tree
  pushdecl_top_level (x)
       tree x;
  {
    register tree t;
    register struct binding_level *b = current_binding_level;
  
    current_binding_level = global_binding_level;
    t = pushdecl (x);
    current_binding_level = b;
    return t;
  }
  
  /* Nonzero if we are currently in the global binding level.  */
  
  int
  global_bindings_p ()
  {
    return current_binding_level == global_binding_level;
  }
  
  /* Return the list of declarations of the current level.
     Note that this list is in reverse order unless/until
     you nreverse it; and when you do nreverse it, you must
     store the result back using `storedecls' or you will lose.  */
  
  tree
  getdecls ()
  {
    return current_binding_level->names;
  }
  
  /* Create a new `struct binding_level'.  */
  
  static struct binding_level *
  make_binding_level ()
  {
    /* NOSTRICT */
    return (struct binding_level *) xmalloc (sizeof (struct binding_level));
  }
  
  void
  pushlevel (unused)
    int unused ATTRIBUTE_UNUSED;
  {
    register struct binding_level *newlevel = NULL_BINDING_LEVEL;
  
  #if 0
    /* If this is the top level of a function,
       just make sure that NAMED_LABELS is 0.  */
  
    if (current_binding_level == global_binding_level)
      named_labels = 0;
  #endif
  
    /* Reuse or create a struct for this binding level.  */
  
    if (free_binding_level)
      {
        newlevel = free_binding_level;
        free_binding_level = free_binding_level->level_chain;
      }
    else
      {
        newlevel = make_binding_level ();
      }
  
    /* Add this level to the front of the chain (stack) of levels that
       are active.  */
  
    *newlevel = clear_binding_level;
    newlevel->level_chain = current_binding_level;
    current_binding_level = newlevel;
  #if defined(DEBUG_JAVA_BINDING_LEVELS)
    newlevel->binding_depth = binding_depth;
    indent ();
    fprintf (stderr, "push %s level 0x%08x pc %d\n",
  	   (is_class_level) ? "class" : "block", newlevel, current_pc);
    is_class_level = 0;
    binding_depth++;
  #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
  }
  
  /* Exit a binding level.
     Pop the level off, and restore the state of the identifier-decl mappings
     that were in effect when this level was entered.
  
     If KEEP is nonzero, this level had explicit declarations, so
     and create a "block" (a BLOCK node) for the level
     to record its declarations and subblocks for symbol table output.
  
     If FUNCTIONBODY is nonzero, this level is the body of a function,
     so create a block as if KEEP were set and also clear out all
     label names.
  
     If REVERSE is nonzero, reverse the order of decls before putting
     them into the BLOCK.  */
  
  tree
  poplevel (keep, reverse, functionbody)
       int keep;
       int reverse;
       int functionbody;
  {
    register tree link;
    /* The chain of decls was accumulated in reverse order.
       Put it into forward order, just for cleanliness.  */
    tree decls;
    tree subblocks = current_binding_level->blocks;
    tree block = 0;
    tree decl;
    int block_previously_created;
  
  #if defined(DEBUG_JAVA_BINDING_LEVELS)
    binding_depth--;
    indent ();
    if (current_binding_level->end_pc != LARGEST_PC)
      fprintf (stderr, "pop  %s level 0x%08x pc %d (end pc %d)\n",
  	     (is_class_level) ? "class" : "block", current_binding_level, current_pc,
  	     current_binding_level->end_pc);
    else
      fprintf (stderr, "pop  %s level 0x%08x pc %d\n",
  	     (is_class_level) ? "class" : "block", current_binding_level, current_pc);
  #if 0
    if (is_class_level != (current_binding_level == class_binding_level))
      {
        indent ();
        fprintf (stderr, "XXX is_class_level != (current_binding_level == class_binding_level)\n");
      }
    is_class_level = 0;
  #endif
  #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
  
    /* Get the decls in the order they were written.
       Usually current_binding_level->names is in reverse order.
       But parameter decls were previously put in forward order.  */
  
    if (reverse)
      current_binding_level->names
        = decls = nreverse (current_binding_level->names);
    else
      decls = current_binding_level->names;
  
    /* Output any nested inline functions within this block
       if they weren't already output.  */
  
    for (decl = decls; decl; decl = TREE_CHAIN (decl))
      if (TREE_CODE (decl) == FUNCTION_DECL
  	&& ! TREE_ASM_WRITTEN (decl)
  	&& DECL_INITIAL (decl) != 0
  	&& TREE_ADDRESSABLE (decl))
        {
  	/* If this decl was copied from a file-scope decl
  	   on account of a block-scope extern decl,
  	   propagate TREE_ADDRESSABLE to the file-scope decl.
  
  	   DECL_ABSTRACT_ORIGIN can be set to itself if warn_return_type is
  	   true, since then the decl goes through save_for_inline_copying.  */
  	if (DECL_ABSTRACT_ORIGIN (decl) != 0
  	    && DECL_ABSTRACT_ORIGIN (decl) != decl)
  	  TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (decl)) = 1;
  	else
  	  {
  	    push_function_context ();
  	    output_inline_function (decl);
  	    pop_function_context ();
  	  }
        }
  
    /* If there were any declarations in that level,
       or if this level is a function body,
       create a BLOCK to record them for the life of this function.  */
  
    block = 0;
    block_previously_created = (current_binding_level->this_block != 0);
    if (block_previously_created)
      block = current_binding_level->this_block;
    else if (keep || functionbody)
      block = make_node (BLOCK);
    if (block != 0)
      {
        BLOCK_VARS (block) = decls;
        BLOCK_SUBBLOCKS (block) = subblocks;
      }
  
    /* In each subblock, record that this is its superior.  */
  
    for (link = subblocks; link; link = TREE_CHAIN (link))
      BLOCK_SUPERCONTEXT (link) = block;
  
    /* Clear out the meanings of the local variables of this level.  */
  
    for (link = decls; link; link = TREE_CHAIN (link))
      {
        tree name = DECL_NAME (link);
        if (name != 0 && IDENTIFIER_LOCAL_VALUE (name) == link)
  	{
  	  /* If the ident. was used or addressed via a local extern decl,
  	     don't forget that fact.  */
  	  if (DECL_EXTERNAL (link))
  	    {
  	      if (TREE_USED (link))
  		TREE_USED (name) = 1;
  	      if (TREE_ADDRESSABLE (link))
  		TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (link)) = 1;
  	    }
  	  IDENTIFIER_LOCAL_VALUE (name) = 0;
  	}
      }
  
    /* Restore all name-meanings of the outer levels
       that were shadowed by this level.  */
  
    for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link))
      IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
  
    /* If the level being exited is the top level of a function,
       check over all the labels, and clear out the current
       (function local) meanings of their names.  */
  
    if (functionbody)
      {
        /* If this is the top level block of a function,
  	 the vars are the function's parameters.
  	 Don't leave them in the BLOCK because they are
  	 found in the FUNCTION_DECL instead.  */
  
        BLOCK_VARS (block) = 0;
  
        /* Clear out the definitions of all label names,
  	 since their scopes end here,
  	 and add them to BLOCK_VARS.  */
  
  #if 0
        for (link = named_labels; link; link = TREE_CHAIN (link))
  	{
  	  register tree label = TREE_VALUE (link);
  
  	  if (DECL_INITIAL (label) == 0)
  	    {
  	      error_with_decl (label, "label `%s' used but not defined");
  	      /* Avoid crashing later.  */
  	      define_label (input_filename, lineno,
  			    DECL_NAME (label));
  	    }
  	  else if (warn_unused[UNUSED_LABEL] && !TREE_USED (label))
  	    warning_with_decl (label, "label `%s' defined but not used");
  	  IDENTIFIER_LABEL_VALUE (DECL_NAME (label)) = 0;
  
  	  /* Put the labels into the "variables" of the
  	     top-level block, so debugger can see them.  */
  	  TREE_CHAIN (label) = BLOCK_VARS (block);
  	  BLOCK_VARS (block) = label;
  	}
  #endif
      }
  
    /* Pop the current level, and free the structure for reuse.  */
  
    {
      register struct binding_level *level = current_binding_level;
      current_binding_level = current_binding_level->level_chain;
  
      level->level_chain = free_binding_level;
      free_binding_level = level;
    }
  
    /* Dispose of the block that we just made inside some higher level.  */
    if (functionbody)
      DECL_INITIAL (current_function_decl) = block;
    else if (block)
      {
        if (!block_previously_created)
          current_binding_level->blocks
            = chainon (current_binding_level->blocks, block);
      }
    /* If we did not make a block for the level just exited,
       any blocks made for inner levels
       (since they cannot be recorded as subblocks in that level)
       must be carried forward so they will later become subblocks
       of something else.  */
    else if (subblocks)
      current_binding_level->blocks
        = chainon (current_binding_level->blocks, subblocks);
  
    /* Set the TYPE_CONTEXTs for all of the tagged types belonging to this
       binding contour so that they point to the appropriate construct, i.e.
       either to the current FUNCTION_DECL node, or else to the BLOCK node
       we just constructed.
  
       Note that for tagged types whose scope is just the formal parameter
       list for some function type specification, we can't properly set
       their TYPE_CONTEXTs here, because we don't have a pointer to the
       appropriate FUNCTION_TYPE node readily available to us.  For those
       cases, the TYPE_CONTEXTs of the relevant tagged type nodes get set
       in `grokdeclarator' as soon as we have created the FUNCTION_TYPE
       node which will represent the "scope" for these "parameter list local"
       tagged types.
    */
  
    if (block)
      TREE_USED (block) = 1;
    return block;
  }
  
  void
  maybe_pushlevels (pc)
       int pc;
  {
  #if defined(DEBUG_JAVA_BINDING_LEVELS)
    current_pc = pc;
  #endif
  
    while (pending_local_decls != NULL_TREE &&
  	 DECL_LOCAL_START_PC (pending_local_decls) <= pc)
      {
        tree *ptr = &pending_local_decls;
        tree decl = *ptr;
        int end_pc = DECL_LOCAL_END_PC (decl);
  
        while (*ptr != NULL_TREE
  	     && DECL_LOCAL_START_PC (*ptr) <= pc
  	     && DECL_LOCAL_END_PC (*ptr) == end_pc)
  	ptr = &TREE_CHAIN (*ptr);
        pending_local_decls = *ptr;
        *ptr = NULL_TREE;
  
        /* Force non-nested range to be nested in current range. */
        if (end_pc > current_binding_level->end_pc)
  	end_pc = current_binding_level->end_pc;
  
        maybe_start_try (pc, end_pc);
        
        pushlevel (1);
        expand_start_bindings (0);
  
        current_binding_level->end_pc = end_pc;
        current_binding_level->start_pc = pc;      
        current_binding_level->names = decl;
        for ( ; decl != NULL_TREE;  decl = TREE_CHAIN (decl))
  	{
  	  push_jvm_slot (DECL_LOCAL_SLOT_NUMBER (decl), decl);
  	}
      }      
  
    maybe_start_try (pc, 0);
  }
  
  void
  maybe_poplevels (pc)
       int pc;
  {
  #if defined(DEBUG_JAVA_BINDING_LEVELS)
    current_pc = pc;
  #endif
  
    while (current_binding_level->end_pc <= pc)
      {
        expand_end_bindings (getdecls (), 1, 0);
        maybe_end_try (current_binding_level->start_pc, pc);
        poplevel (1, 0, 0);
      }
    maybe_end_try (0, pc);
  }
  
  /* Terminate any binding which began during the range beginning at
     start_pc.  This tidies up improperly nested local variable ranges
     and exception handlers; a variable declared within an exception
     range is forcibly terminated when that exception ends. */
  
  void
  force_poplevels (start_pc)
       int start_pc;
  {
    while (current_binding_level->start_pc > start_pc)
      {
        if (pedantic && current_binding_level->start_pc > start_pc)
  	warning_with_decl (current_function_decl, 
  			   "In %s: overlapped variable and exception ranges at %d",
  			   current_binding_level->start_pc);
        expand_end_bindings (getdecls (), 1, 0);
        poplevel (1, 0, 0);
      }
  }
  
  /* Insert BLOCK at the end of the list of subblocks of the
     current binding level.  This is used when a BIND_EXPR is expanded,
     to handle the BLOCK node inside the BIND_EXPR.  */
  
  void
  insert_block (block)
       tree block;
  {
    TREE_USED (block) = 1;
    current_binding_level->blocks
      = chainon (current_binding_level->blocks, block);
  }
  
  /* Set the BLOCK node for the innermost scope
     (the one we are currently in).  */
  
  void
  set_block (block)
       register tree block;
  {
    current_binding_level->this_block = block;
    current_binding_level->names = chainon (current_binding_level->names,
  					  BLOCK_VARS (block));
    current_binding_level->blocks = chainon (current_binding_level->blocks,
  					   BLOCK_SUBBLOCKS (block));
  }
  
  /* integrate_decl_tree calls this function. */
  
  void
  copy_lang_decl (node)
       tree node;
  {
    int lang_decl_size
      = TREE_CODE (node) == VAR_DECL ? sizeof (struct lang_decl_var)
      : sizeof (struct lang_decl);
    struct lang_decl *x = (struct lang_decl *) ggc_alloc (lang_decl_size);
    memcpy (x, DECL_LANG_SPECIFIC (node), lang_decl_size);
    DECL_LANG_SPECIFIC (node) = x;
  }
  
  /* If DECL has a cleanup, build and return that cleanup here.
     This is a callback called by expand_expr.  */
  
  tree
  maybe_build_cleanup (decl)
    tree decl ATTRIBUTE_UNUSED;
  {
    /* There are no cleanups in Java (I think).  */
    return NULL_TREE;
  }
  
  void
  give_name_to_locals (jcf)
       JCF *jcf;
  {
    int i, n = DECL_LOCALVARIABLES_OFFSET (current_function_decl);
    int code_offset = DECL_CODE_OFFSET (current_function_decl);
    tree parm;
    pending_local_decls = NULL_TREE;
    if (n == 0)
      return;
    JCF_SEEK (jcf, n);
    n = JCF_readu2 (jcf);
    for (i = 0; i < n; i++)
      {
        int start_pc = JCF_readu2 (jcf);
        int length = JCF_readu2 (jcf);
        int name_index = JCF_readu2 (jcf);
        int signature_index = JCF_readu2 (jcf);
        int slot = JCF_readu2 (jcf);
        tree name = get_name_constant (jcf, name_index);
        tree type = parse_signature (jcf, signature_index);
        if (slot < DECL_ARG_SLOT_COUNT (current_function_decl)
  	  && start_pc == 0
  	  && length == DECL_CODE_LENGTH (current_function_decl))
  	{
  	  tree decl = TREE_VEC_ELT (decl_map, slot);
  	  DECL_NAME (decl) = name;
  	  SET_DECL_ASSEMBLER_NAME (decl, name);
  	  if (TREE_CODE (decl) != PARM_DECL || TREE_TYPE (decl) != type)
  	    warning ("bad type in parameter debug info");
  	}
        else
  	{
  	  tree *ptr;
  	  int end_pc = start_pc + length;
  	  tree decl = build_decl (VAR_DECL, name, type);
  	  if (end_pc > DECL_CODE_LENGTH (current_function_decl))
  	    {
  	      warning_with_decl (decl,
  			 "bad PC range for debug info for local `%s'");
  	      end_pc = DECL_CODE_LENGTH (current_function_decl);
  	    }
  
  	  /* Adjust start_pc if necessary so that the local's first
  	     store operation will use the relevant DECL as a
  	     destination. Fore more information, read the leading
  	     comments for expr.c:maybe_adjust_start_pc. */
  	  start_pc = maybe_adjust_start_pc (jcf, code_offset, start_pc, slot);
  
  	  MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
  	  DECL_LOCAL_SLOT_NUMBER (decl) = slot;
  	  DECL_LOCAL_START_PC (decl) = start_pc;
  #if 0
  	  /* FIXME: The range used internally for exceptions and local
  	     variable ranges, is a half-open interval: 
  	     start_pc <= pc < end_pc.  However, the range used in the
  	     Java VM spec is inclusive at both ends: 
  	     start_pc <= pc <= end_pc. */
  	  end_pc++;
  #endif
  	  DECL_LOCAL_END_PC (decl) = end_pc;
  
  	  /* Now insert the new decl in the proper place in
  	     pending_local_decls.  We are essentially doing an insertion sort,
  	     which works fine, since the list input will normally already
  	     be sorted. */
  	  ptr = &pending_local_decls;
  	  while (*ptr != NULL_TREE
  		 && (DECL_LOCAL_START_PC (*ptr) > start_pc
  		     || (DECL_LOCAL_START_PC (*ptr) == start_pc
  			 && DECL_LOCAL_END_PC (*ptr) < end_pc)))
  	    ptr = &TREE_CHAIN (*ptr);
  	  TREE_CHAIN (decl) = *ptr;
  	  *ptr = decl;
  	}
      }
  
    pending_local_decls = nreverse (pending_local_decls);
  
    /* Fill in default names for the parameters. */ 
    for (parm = DECL_ARGUMENTS (current_function_decl), i = 0;
         parm != NULL_TREE;  parm = TREE_CHAIN (parm), i++)
      {
        if (DECL_NAME (parm) == NULL_TREE)
  	{
  	  int arg_i = METHOD_STATIC (current_function_decl) ? i+1 : i;
  	  if (arg_i == 0)
  	    DECL_NAME (parm) = get_identifier ("this");
  	  else
  	    {
  	      char buffer[12];
  	      sprintf (buffer, "ARG_%d", arg_i);
  	      DECL_NAME (parm) = get_identifier (buffer);
  	    }
  	  SET_DECL_ASSEMBLER_NAME (parm, DECL_NAME (parm));
  	}
      }
  }
  
  tree
  build_result_decl (fndecl)
    tree fndecl;
  {
    tree restype = TREE_TYPE (TREE_TYPE (fndecl));
    /* To be compatible with C_PROMOTING_INTEGER_TYPE_P in cc1/cc1plus. */
    if (INTEGRAL_TYPE_P (restype)
        && TYPE_PRECISION (restype) < TYPE_PRECISION (integer_type_node))
      restype = integer_type_node;
    return (DECL_RESULT (fndecl) = build_decl (RESULT_DECL, NULL_TREE, restype));
  }
  
  void
  complete_start_java_method (fndecl)
    tree fndecl;
  {
    if (! flag_emit_class_files)
      {
        /* Initialize the RTL code for the function.  */
        init_function_start (fndecl, input_filename, lineno);
  
        /* Set up parameters and prepare for return, for the function.  */
        expand_function_start (fndecl, 0);
      }
  
  #if 0
        /* If this fcn was already referenced via a block-scope `extern' decl (or
           an implicit decl), propagate certain information about the usage. */
        if (TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (current_function_decl)))
          TREE_ADDRESSABLE (current_function_decl) = 1;
  
  #endif
  
    if (METHOD_STATIC (fndecl) && ! METHOD_PRIVATE (fndecl)
        && ! flag_emit_class_files
        && ! DECL_CLINIT_P (fndecl)
        && ! CLASS_INTERFACE (TYPE_NAME (current_class)))
      {
        tree clas = DECL_CONTEXT (fndecl);
        tree init = build (CALL_EXPR, void_type_node,
  			 build_address_of (soft_initclass_node),
  			 build_tree_list (NULL_TREE, build_class_ref (clas)),
  			 NULL_TREE);
        TREE_SIDE_EFFECTS (init) = 1;
        expand_expr_stmt (init);
      }
  
    /* Push local variables. Function compiled from source code are
       using a different local variables management, and for them,
       pushlevel shouldn't be called from here.  */
    if (!CLASS_FROM_SOURCE_P (DECL_CONTEXT (fndecl)))
      {
        pushlevel (2);
        if (! flag_emit_class_files)
  	expand_start_bindings (1);
      }
  
    if (METHOD_SYNCHRONIZED (fndecl) && ! flag_emit_class_files)
      {
        /* Wrap function body with a monitorenter plus monitorexit cleanup. */
        tree enter, exit, lock;
        if (METHOD_STATIC (fndecl))
  	lock = build_class_ref (DECL_CONTEXT (fndecl));
        else
  	lock = DECL_ARGUMENTS (fndecl);
        BUILD_MONITOR_ENTER (enter, lock);
        BUILD_MONITOR_EXIT (exit, lock);
        if (!CLASS_FROM_SOURCE_P (DECL_CONTEXT (fndecl)))
  	{
  	  expand_expr_stmt (enter);
  	  expand_decl_cleanup (NULL_TREE, exit);
  	}
        else
  	{
  	  tree function_body = DECL_FUNCTION_BODY (fndecl);
  	  tree body = BLOCK_EXPR_BODY (function_body);
  	  lock = build (COMPOUND_EXPR, void_type_node,
  			enter,
  			build (TRY_FINALLY_EXPR, void_type_node, body, exit));
  	  TREE_SIDE_EFFECTS (lock) = 1;
  	  BLOCK_EXPR_BODY (function_body) = lock;
  	}
      }
  }
  
  void
  start_java_method (fndecl)
       tree fndecl;
  {
    tree tem, *ptr;
    int i;
  
    current_function_decl = fndecl;
    announce_function (fndecl);
  
    i = DECL_MAX_LOCALS(fndecl) + DECL_MAX_STACK(fndecl);
    decl_map = make_tree_vec (i);
    type_map = (tree *) xrealloc (type_map, i * sizeof (tree));
  
  #if defined(DEBUG_JAVA_BINDING_LEVELS)
    fprintf (stderr, "%s:\n", (*decl_printable_name) (fndecl, 2));
    current_pc = 0;
  #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
    pushlevel (1);  /* Push parameters. */
  
    ptr = &DECL_ARGUMENTS (fndecl);
    for (tem = TYPE_ARG_TYPES (TREE_TYPE (fndecl)), i = 0;
         tem != end_params_node; tem = TREE_CHAIN (tem), i++)
      {
        tree parm_name = NULL_TREE, parm_decl;
        tree parm_type = TREE_VALUE (tem);
        if (i >= DECL_MAX_LOCALS (fndecl))
  	abort ();
  
        parm_decl = build_decl (PARM_DECL, parm_name, parm_type);
        DECL_CONTEXT (parm_decl) = fndecl;
        if (PROMOTE_PROTOTYPES
  	  && TYPE_PRECISION (parm_type) < TYPE_PRECISION (integer_type_node)
  	  && INTEGRAL_TYPE_P (parm_type))
  	parm_type = integer_type_node;
        DECL_ARG_TYPE (parm_decl) = parm_type;
  
        *ptr = parm_decl;
        ptr = &TREE_CHAIN (parm_decl);
  
        /* Add parm_decl to the decl_map. */
        push_jvm_slot (i, parm_decl);
  
        type_map[i] = TREE_TYPE (parm_decl);
        if (TYPE_IS_WIDE (TREE_TYPE (parm_decl)))
  	{
  	  i++;
  	  type_map[i] = void_type_node;
  	}
      }
    *ptr = NULL_TREE;
    DECL_ARG_SLOT_COUNT (current_function_decl) = i;
  
    while (i < DECL_MAX_LOCALS(fndecl))
      type_map[i++] = NULL_TREE;
  
    build_result_decl (fndecl);
    complete_start_java_method (fndecl);
  }
  
  void
  end_java_method ()
  {
    tree fndecl = current_function_decl;
  
    expand_end_bindings (getdecls (), 1, 0);
    /* pop out of function */
    poplevel (1, 1, 0);
  
    /* pop out of its parameters */
    poplevel (1, 0, 1);
  
    BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl;
  
    /* Generate rtl for function exit.  */
    expand_function_end (input_filename, lineno, 0);
  
    /* Run the optimizers and output assembler code for this function. */
    rest_of_compilation (fndecl);
  
    current_function_decl = NULL_TREE;
  }
  
  /* Mark language-specific parts of T for garbage-collection.  */
  
  void
  lang_mark_tree (t)
       tree t;
  {
    if (TREE_CODE (t) == IDENTIFIER_NODE)
      {
        struct lang_identifier *li = (struct lang_identifier *) t;
        ggc_mark_tree (li->global_value);
        ggc_mark_tree (li->local_value);
        ggc_mark_tree (li->utf8_ref);
      }
    else if (TREE_CODE (t) == VAR_DECL
  	   || TREE_CODE (t) == PARM_DECL
  	   || TREE_CODE (t) == FIELD_DECL)
      {
        struct lang_decl_var *ldv = 
  	((struct lang_decl_var *) DECL_LANG_SPECIFIC (t));
        if (ldv)
  	{
  	  ggc_mark (ldv);
  	  ggc_mark_tree (ldv->slot_chain);
  	  ggc_mark_tree (ldv->am);
  	  ggc_mark_tree (ldv->wfl);
  	}
      }
    else if (TREE_CODE (t) == FUNCTION_DECL)
      {
        struct lang_decl *ld = DECL_LANG_SPECIFIC (t);
        
        if (ld)
  	{
  	  ggc_mark (ld);
  	  ggc_mark_tree (ld->wfl);
  	  ggc_mark_tree (ld->throws_list);
  	  ggc_mark_tree (ld->function_decl_body);
  	  ggc_mark_tree (ld->called_constructor);
  	  ggc_mark_tree (ld->inner_access);
  	  ggc_mark_tree_hash_table (&ld->init_test_table);
  	  ggc_mark_tree_hash_table (&ld->ict);
  	  ggc_mark_tree (ld->smic);
  	}
      }
    else if (TYPE_P (t))
      {
        struct lang_type *lt = TYPE_LANG_SPECIFIC (t);
        
        if (lt)
  	{
  	  ggc_mark (lt);
  	  ggc_mark_tree (lt->signature);
  	  ggc_mark_tree (lt->cpool_data_ref);
  	  ggc_mark_tree (lt->finit_stmt_list);
  	  ggc_mark_tree (lt->clinit_stmt_list);
  	  ggc_mark_tree (lt->ii_block);
  	  ggc_mark_tree (lt->dot_class);
  	  ggc_mark_tree (lt->package_list);
  	}
      }
  }
  