OSDN Git Service

PR middle-end/46314
[pf3gnuchains/gcc-fork.git] / gcc / java / expr.c
index c51b5cd..85cf1a2 100644 (file)
@@ -1,12 +1,12 @@
 /* Process expressions for the GNU compiler for the Java(TM) language.
    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-   2005, 2006, 2007 Free Software Foundation, Inc.
+   2005, 2006, 2007, 2008, 2010 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC 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)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GCC is distributed in the hope that it will be useful,
@@ -15,9 +15,8 @@ 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 GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  
 
 Java and all Java-based marks are trademarks or registered trademarks
 of Sun Microsystems, Inc. in the United States and other countries.
@@ -28,22 +27,18 @@ The Free Software Foundation is independent of Sun Microsystems, Inc.  */
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
 #include "tree.h"
-#include "real.h"
-#include "rtl.h"
 #include "flags.h"
-#include "expr.h"
 #include "java-tree.h"
 #include "javaop.h"
 #include "java-opcodes.h"
 #include "jcf.h"
 #include "java-except.h"
 #include "parse.h"
+#include "diagnostic-core.h"
 #include "toplev.h"
-#include "except.h"
 #include "ggc.h"
-#include "tree-gimple.h"
+#include "tree-iterator.h"
 #include "target.h"
 
 static void flush_quick_stack (void);
@@ -74,7 +69,7 @@ static void expand_cond (enum tree_code, tree, int);
 static void expand_java_goto (int);
 static tree expand_java_switch (tree, int);
 static void expand_java_add_case (tree, int, int);
-static tree pop_arguments (tree); 
+static VEC(tree,gc) *pop_arguments (tree); 
 static void expand_invoke (int, int, int); 
 static void expand_java_field_op (int, int, int); 
 static void java_push_constant_from_pool (struct JCF *, int); 
@@ -83,6 +78,7 @@ static tree build_java_throw_out_of_bounds_exception (tree);
 static tree build_java_check_indexed_type (tree, tree); 
 static unsigned char peek_opcode_at_pc (struct JCF *, int, int);
 static void promote_arguments (void);
+static void cache_cpool_data_ref (void);
 
 static GTY(()) tree operand_type[59];
 
@@ -95,8 +91,8 @@ tree dtable_ident = NULL_TREE;
 int always_initialize_class_p = 0;
 
 /* We store the stack state in two places:
-   Within a basic block, we use the quick_stack, which is a
-   pushdown list (TREE_LISTs) of expression nodes.
+   Within a basic block, we use the quick_stack, which is a VEC of expression
+   nodes.
    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
    to the stack slot array (as handled by find_stack_slot).
@@ -121,10 +117,7 @@ int always_initialize_class_p = 0;
    So dup cannot just add an extra element to the quick_stack, but iadd can.
 */
 
-static GTY(()) tree quick_stack;
-
-/* A free-list of unused permanent TREE_LIST nodes.  */
-static GTY((deletable)) tree tree_list_free_list;
+static GTY(()) VEC(tree,gc) *quick_stack;
 
 /* The physical memory page size used in this computer.  See
    build_field_ref().  */
@@ -220,33 +213,24 @@ static void
 flush_quick_stack (void)
 {
   int stack_index = stack_pointer;
-  tree prev, cur, next;
+  unsigned ix;
+  tree t;
 
-  /* 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)
-    {
-      next = TREE_CHAIN (cur);
-      TREE_CHAIN (cur) = prev;
-      prev = cur;
-      stack_index -= 1 + TYPE_IS_WIDE (TREE_TYPE (TREE_VALUE (cur)));
-    }
-  quick_stack = prev;
+  /* Count the number of slots the quick stack is holding.  */
+  for (ix = 0; VEC_iterate(tree, quick_stack, ix, t); ix++)
+    stack_index -= 1 + TYPE_IS_WIDE (TREE_TYPE (t));
 
-  while (quick_stack != NULL_TREE)
+  for (ix = 0; VEC_iterate(tree, quick_stack, ix, t); ix++)
     {
-      tree decl;
-      tree node = quick_stack, type;
-      quick_stack = TREE_CHAIN (node);
-      TREE_CHAIN (node) = tree_list_free_list;
-      tree_list_free_list = node;
-      node = TREE_VALUE (node);
-      type = TREE_TYPE (node);
+      tree decl, type = TREE_TYPE (t);
 
       decl = find_stack_slot (stack_index, type);
-      if (decl != node)
-       java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (node), decl, node));
+      if (decl != t)
+       java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (t), decl, t));
       stack_index += 1 + TYPE_IS_WIDE (type);
     }
+
+  VEC_truncate (tree, quick_stack, 0);
 }
 
 /* Push TYPE on the type stack.
@@ -287,16 +271,8 @@ push_value (tree value)
       value = convert (type, value);
     }
   push_type (type);
-  if (tree_list_free_list == NULL_TREE)
-    quick_stack = tree_cons (NULL_TREE, value, quick_stack);
-  else
-    {
-      tree node = tree_list_free_list;
-      tree_list_free_list = TREE_CHAIN (tree_list_free_list);
-      TREE_VALUE (node) = value;
-      TREE_CHAIN (node) = quick_stack;
-      quick_stack = node;
-    }
+  VEC_safe_push (tree, gc, quick_stack, value);
+
   /* 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
      quick stack and is then popped, this won't happen -- so we flush
@@ -418,8 +394,8 @@ pop_type (tree type)
 static int
 type_assertion_eq (const void * k1_p, const void * k2_p)
 {
-  type_assertion k1 = *(type_assertion *)k1_p;
-  type_assertion k2 = *(type_assertion *)k2_p;
+  const type_assertion k1 = *(const type_assertion *)k1_p;
+  const type_assertion k2 = *(const type_assertion *)k2_p;
   return (k1.assertion_code == k2.assertion_code
           && k1.op1 == k2.op1
          && k1.op2 == k2.op2);
@@ -430,28 +406,47 @@ type_assertion_eq (const void * k1_p, const void * k2_p)
 static hashval_t
 type_assertion_hash (const void *p)
 {
-  const type_assertion *k_p = p;
+  const type_assertion *k_p = (const type_assertion *) p;
   hashval_t hash = iterative_hash (&k_p->assertion_code, sizeof
                                   k_p->assertion_code, 0);
-  hash = iterative_hash (&k_p->op1, sizeof k_p->op1, hash);
-  return iterative_hash (&k_p->op2, sizeof k_p->op2, hash);
+
+  switch (k_p->assertion_code)
+    {
+    case JV_ASSERT_TYPES_COMPATIBLE:
+      hash = iterative_hash (&TYPE_UID (k_p->op2), sizeof TYPE_UID (k_p->op2),
+                            hash);
+      /* Fall through.  */
+
+    case JV_ASSERT_IS_INSTANTIABLE:
+      hash = iterative_hash (&TYPE_UID (k_p->op1), sizeof TYPE_UID (k_p->op1),
+                            hash);
+      /* Fall through.  */
+
+    case JV_ASSERT_END_OF_TABLE:
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return hash;
 }
 
 /* Add an entry to the type assertion table for the given class.  
-   CLASS 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.
    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
    specific to each assertion_code. */
 
 void
-add_type_assertion (tree class, int assertion_code, tree op1, tree op2)
+add_type_assertion (tree klass, int assertion_code, tree op1, tree op2)
 {
   htab_t assertions_htab;
   type_assertion as;
   void **as_pp;
 
-  assertions_htab = TYPE_ASSERTIONS (class);
+  assertions_htab = TYPE_ASSERTIONS (klass);
   if (assertions_htab == NULL)
     {
       assertions_htab = htab_create_ggc (7, type_assertion_hash, 
@@ -469,7 +464,7 @@ add_type_assertion (tree class, int assertion_code, tree op1, tree op2)
   if (*as_pp)
     return;
 
-  *as_pp = ggc_alloc (sizeof (type_assertion));
+  *as_pp = ggc_alloc_type_assertion ();
   **(type_assertion **)as_pp = as;
 }
 
@@ -590,15 +585,8 @@ static tree
 pop_value (tree type)
 {
   type = pop_type (type);
-  if (quick_stack)
-    {
-      tree node = quick_stack;
-      quick_stack = TREE_CHAIN (quick_stack);
-      TREE_CHAIN (node) = tree_list_free_list;
-      tree_list_free_list = node;
-      node = TREE_VALUE (node);
-      return node;
-    }
+  if (VEC_length (tree, quick_stack) != 0)
+    return VEC_pop (tree, quick_stack);
   else
     return find_stack_slot (stack_pointer, promote_type (type));
 }
@@ -611,7 +599,7 @@ java_stack_pop (int count)
 {
   while (count > 0)
     {
-      tree type, val;
+      tree type;
 
       gcc_assert (stack_pointer != 0);
 
@@ -623,7 +611,7 @@ java_stack_pop (int count)
 
          type = stack_type_map[stack_pointer - 2];
        }
-      val = pop_value (type);
+      pop_value (type);
       count--;
     }
 }
@@ -638,9 +626,8 @@ java_stack_swap (void)
   tree decl1, decl2;
 
   if (stack_pointer < 2
-      || (type1 = stack_type_map[stack_pointer - 1]) == TYPE_UNKNOWN
-      || (type2 = stack_type_map[stack_pointer - 2]) == TYPE_UNKNOWN
-      || type1 == TYPE_SECOND || type2 == TYPE_SECOND
+      || (type1 = stack_type_map[stack_pointer - 1]) == TYPE_SECOND
+      || (type2 = stack_type_map[stack_pointer - 2]) == TYPE_SECOND
       || TYPE_IS_WIDE (type1) || TYPE_IS_WIDE (type2))
     /* Bad stack swap.  */
     abort ();
@@ -649,7 +636,7 @@ java_stack_swap (void)
   flush_quick_stack ();
   decl1 = find_stack_slot (stack_pointer - 1, type1);
   decl2 = find_stack_slot (stack_pointer - 2, type2);
-  temp = build_decl (VAR_DECL, NULL_TREE, type1);
+  temp = build_decl (input_location, VAR_DECL, NULL_TREE, type1);
   java_add_local_var (temp);
   java_add_stmt (build2 (MODIFY_EXPR, type1, temp, decl1));
   java_add_stmt (build2 (MODIFY_EXPR, type2, 
@@ -715,11 +702,9 @@ build_java_athrow (tree node)
 {
   tree call;
 
-  call = build3 (CALL_EXPR,
-                void_type_node,
-                build_address_of (throw_node),
-                build_tree_list (NULL_TREE, node),
-                NULL_TREE);
+  call = build_call_nary (void_type_node,
+                         build_address_of (throw_node),
+                         1, node);
   TREE_SIDE_EFFECTS (call) = 1;
   java_add_stmt (call);
   java_stack_pop (stack_pointer);
@@ -798,10 +783,20 @@ encode_newarray_type (tree type)
 static tree
 build_java_throw_out_of_bounds_exception (tree index)
 {
-  tree node = build3 (CALL_EXPR, int_type_node,
-                     build_address_of (soft_badarrayindex_node), 
-                     build_tree_list (NULL_TREE, index), NULL_TREE);
+  tree node;
+
+  /* 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
+     to int_type_node because we would lose it during gimplification.  */
+  gcc_assert (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (soft_badarrayindex_node))));
+  node = build_call_nary (void_type_node,
+                              build_address_of (soft_badarrayindex_node),
+                              1, index);
+  TREE_SIDE_EFFECTS (node) = 1;
+
+  node = build2 (COMPOUND_EXPR, int_type_node, node, integer_zero_node);
   TREE_SIDE_EFFECTS (node) = 1;        /* Allows expansion within ANDIF */
+
   return (node);
 }
 
@@ -849,9 +844,9 @@ java_check_reference (tree expr, int check)
       expr = build3 (COND_EXPR, TREE_TYPE (expr),
                     build2 (EQ_EXPR, boolean_type_node,
                             expr, null_pointer_node),
-                    build3 (CALL_EXPR, void_type_node, 
-                            build_address_of (soft_nullpointer_node),
-                            NULL_TREE, NULL_TREE),
+                    build_call_nary (void_type_node, 
+                                     build_address_of (soft_nullpointer_node),
+                                     0),
                     expr);
     }
 
@@ -877,7 +872,7 @@ build_java_indirect_ref (tree type, tree expr, int check)
 tree
 build_java_arrayaccess (tree array, tree type, tree index)
 {
-  tree node, throw = NULL_TREE;
+  tree node, throw_expr = NULL_TREE;
   tree data_field;
   tree ref;
   tree array_type = TREE_TYPE (TREE_TYPE (array));
@@ -905,17 +900,18 @@ build_java_arrayaccess (tree array, tree type, tree index)
                          len);
       if (! integer_zerop (test))
        {
-         throw = build2 (TRUTH_ANDIF_EXPR, int_type_node, test,
-                         build_java_throw_out_of_bounds_exception (index));
+         throw_expr
+           = build2 (TRUTH_ANDIF_EXPR, int_type_node, test,
+                     build_java_throw_out_of_bounds_exception (index));
          /* allows expansion within COMPOUND */
-         TREE_SIDE_EFFECTS( throw ) = 1;
+         TREE_SIDE_EFFECTS( throw_expr ) = 1;
        }
     }
 
   /* If checking bounds, wrap the index expr with a COMPOUND_EXPR in order
      to have the bounds check evaluated first. */
-  if (throw != NULL_TREE)
-    index = build2 (COMPOUND_EXPR, int_type_node, throw, index);
+  if (throw_expr != NULL_TREE)
+    index = build2 (COMPOUND_EXPR, int_type_node, throw_expr, index);
 
   data_field = lookup_field (&array_type, get_identifier ("data"));
 
@@ -930,13 +926,12 @@ build_java_arrayaccess (tree array, tree type, tree index)
 
   /* Multiply the index by the size of an element to obtain a byte
      offset.  Convert the result to a pointer to the element type.  */
-  index = fold_convert (TREE_TYPE (node),
-                       build2 (MULT_EXPR, sizetype, 
-                               fold_convert (sizetype, index), 
-                               size_exp));
+  index = build2 (MULT_EXPR, sizetype, 
+                 fold_convert (sizetype, index), 
+                 size_exp);
 
   /* Sum the byte offset and the address of the data field.  */
-  node = fold_build2 (PLUS_EXPR, TREE_TYPE (node), node, index);
+  node = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (node), node, index);
 
   /* Finally, return
 
@@ -1013,11 +1008,9 @@ build_java_arraystore_check (tree array, tree object)
     }
 
   /* Build an invocation of _Jv_CheckArrayStore */
-  check = build3 (CALL_EXPR, void_type_node,
-                 build_address_of (soft_checkarraystore_node),
-                 tree_cons (NULL_TREE, array,
-                            build_tree_list (NULL_TREE, object)),
-                 NULL_TREE);
+  check = build_call_nary (void_type_node,
+                          build_address_of (soft_checkarraystore_node),
+                          2, array, object);
   TREE_SIDE_EFFECTS (check) = 1;
 
   return check;
@@ -1059,12 +1052,9 @@ build_newarray (int atype_value, tree length)
      some work.  */
   type_arg = build_class_ref (prim_type);
 
-  return build3 (CALL_EXPR, promote_type (type),
-                build_address_of (soft_newarray_node),
-                tree_cons (NULL_TREE, 
-                           type_arg,
-                           build_tree_list (NULL_TREE, length)),
-                NULL_TREE);
+  return build_call_nary (promote_type (type),
+                         build_address_of (soft_newarray_node),
+                         2, type_arg, length);
 }
 
 /* Generates anewarray from a given CLASS_TYPE. Gets from the stack the size
@@ -1078,13 +1068,12 @@ build_anewarray (tree class_type, tree length)
                             host_integerp (length, 0)
                             ? tree_low_cst (length, 0) : -1);
 
-  return build3 (CALL_EXPR, promote_type (type),
-                build_address_of (soft_anewarray_node),
-                tree_cons (NULL_TREE, length,
-                           tree_cons (NULL_TREE, build_class_ref (class_type),
-                                      build_tree_list (NULL_TREE,
-                                                       null_pointer_node))),
-                NULL_TREE);
+  return build_call_nary (promote_type (type),
+                         build_address_of (soft_anewarray_node),
+                         3,
+                         length,
+                         build_class_ref (class_type),
+                         null_pointer_node);
 }
 
 /* Return a node the evaluates 'new TYPE[LENGTH]'. */
@@ -1106,19 +1095,21 @@ static void
 expand_java_multianewarray (tree class_type, int ndim)
 {
   int i;
-  tree args = build_tree_list( NULL_TREE, null_pointer_node );
+  VEC(tree,gc) *args = NULL;
 
-  for( i = 0; i < ndim; i++ )
-    args = tree_cons (NULL_TREE, pop_value (int_type_node), args);
+  VEC_safe_grow (tree, gc, args, 3 + ndim);
 
-  push_value (build3 (CALL_EXPR,
-                     promote_type (class_type),
-                     build_address_of (soft_multianewarray_node),
-                     tree_cons (NULL_TREE, build_class_ref (class_type),
-                                tree_cons (NULL_TREE, 
-                                           build_int_cst (NULL_TREE, ndim),
-                                           args)),
-                     NULL_TREE));
+  VEC_replace (tree, args, 0, build_class_ref (class_type));
+  VEC_replace (tree, args, 1, build_int_cst (NULL_TREE, ndim));
+
+  for(i = ndim - 1; i >= 0; i-- )
+    VEC_replace (tree, args, (unsigned)(2 + i), pop_value (int_type_node));
+
+  VEC_replace (tree, args, 2 + ndim, null_pointer_node);
+
+  push_value (build_call_vec (promote_type (class_type),
+                              build_address_of (soft_multianewarray_node),
+                              args));
 }
 
 /*  ARRAY[INDEX] <- RHS. build_java_check_indexed_type makes sure that
@@ -1169,7 +1160,7 @@ expand_java_arraystore (tree rhs_type_node)
      MODIFY_EXPR to set the array element.  */
 
   access = build_java_arrayaccess (array, rhs_type_node, index);
-  temp = build_decl (VAR_DECL, NULL_TREE, 
+  temp = build_decl (input_location, VAR_DECL, NULL_TREE, 
                     build_pointer_type (TREE_TYPE (access)));
   java_add_local_var (temp);
   java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (temp),
@@ -1245,11 +1236,9 @@ expand_java_array_length (void)
 static tree
 build_java_monitor (tree call, tree object)
 {
-  return build3 (CALL_EXPR,
-                void_type_node,
-                build_address_of (call),
-                build_tree_list (NULL_TREE, object),
-                NULL_TREE);
+  return build_call_nary (void_type_node,
+                         build_address_of (call),
+                         1, object);
 }
 
 /* Emit code for one of the PUSHC instructions. */
@@ -1295,7 +1284,7 @@ expand_java_return (tree type)
        retval = build1(NOP_EXPR, TREE_TYPE(res), retval);
       
       TREE_SIDE_EFFECTS (retval) = 1;
-      java_add_stmt (build1 (RETURN_EXPR, TREE_TYPE (retval), retval));
+      java_add_stmt (build1 (RETURN_EXPR, void_type_node, retval));
     }
 }
 
@@ -1311,7 +1300,7 @@ expand_load_internal (int index, tree type, int pc)
      generated.  To avoid this we create a new local and copy our
      value into it.  Then we push this new local on the stack.
      Hopefully this all gets optimized out.  */
-  copy = build_decl (VAR_DECL, NULL_TREE, type);
+  copy = build_decl (input_location, VAR_DECL, NULL_TREE, type);
   if ((INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))
       && TREE_TYPE (copy) != TREE_TYPE (var))
     var = convert (type, var);
@@ -1346,10 +1335,9 @@ java_create_object (tree type)
                     ? alloc_object_node
                     : alloc_no_finalizer_node);
   
-  return build3 (CALL_EXPR, promote_type (type),
-                build_address_of (alloc_node),
-                build_tree_list (NULL_TREE, build_class_ref (type)),
-                NULL_TREE);
+  return build_call_nary (promote_type (type),
+                         build_address_of (alloc_node),
+                         1, build_class_ref (type));
 }
 
 static void
@@ -1362,10 +1350,9 @@ expand_java_NEW (tree type)
   if (! CLASS_LOADED_P (type))
     load_class (type, 1);
   safe_layout_class (type);
-  push_value (build3 (CALL_EXPR, promote_type (type),
-                     build_address_of (alloc_node),
-                     build_tree_list (NULL_TREE, build_class_ref (type)),
-                     NULL_TREE));
+  push_value (build_call_nary (promote_type (type),
+                              build_address_of (alloc_node),
+                              1, build_class_ref (type)));
 }
 
 /* This returns an expression which will extract the class of an
@@ -1444,12 +1431,9 @@ build_instanceof (tree value, tree type)
     }
   else
     {
-      expr = build3 (CALL_EXPR, itype,
-                    build_address_of (soft_instanceof_node),
-                    tree_cons (NULL_TREE, value,
-                               build_tree_list (NULL_TREE,
-                                                build_class_ref (type))),
-                    NULL_TREE);
+      expr = build_call_nary (itype,
+                             build_address_of (soft_instanceof_node),
+                             2, value, build_class_ref (type));
     }
   TREE_SIDE_EFFECTS (expr) = TREE_SIDE_EFFECTS (value);
   return expr;
@@ -1467,11 +1451,9 @@ static void
 expand_java_CHECKCAST (tree type)
 {
   tree value = pop_value (ptr_type_node);
-  value = build3 (CALL_EXPR, promote_type (type),
-                 build_address_of (soft_checkcast_node),
-                 tree_cons (NULL_TREE, build_class_ref (type),
-                            build_tree_list (NULL_TREE, value)),
-                 NULL_TREE);
+  value = build_call_nary (promote_type (type),
+                          build_address_of (soft_checkcast_node),
+                          2, build_class_ref (type), value);
   push_value (value);
 }
 
@@ -1526,12 +1508,7 @@ build_java_soft_divmod (enum tree_code op, tree type, tree op1, tree op2)
     }
 
   gcc_assert (call);
-  call = build3 (CALL_EXPR, type,
-                build_address_of (call),
-                tree_cons (NULL_TREE, arg1,
-                           build_tree_list (NULL_TREE, arg2)),
-                NULL_TREE);
-         
+  call = build_call_nary (type, build_address_of (call), 2, arg1, arg2);
   return call;
 }
 
@@ -1543,7 +1520,7 @@ build_java_binop (enum tree_code op, tree type, tree arg1, tree arg2)
     {
     case URSHIFT_EXPR:
       {
-       tree u_type = java_unsigned_type (type);
+       tree u_type = unsigned_type_for (type);
        arg1 = convert (u_type, arg1);
        arg1 = build_java_binop (RSHIFT_EXPR, u_type, arg1, arg2);
        return convert (type, arg1);
@@ -1594,11 +1571,9 @@ build_java_binop (enum tree_code op, tree type, tree arg1, tree arg2)
              arg1 = convert (double_type_node, arg1);
              arg2 = convert (double_type_node, arg2);
            }
-         call = build3 (CALL_EXPR, double_type_node,
-                        build_address_of (soft_fmod_node),
-                        tree_cons (NULL_TREE, arg1,
-                                   build_tree_list (NULL_TREE, arg2)),
-                        NULL_TREE);
+         call = build_call_nary (double_type_node,
+                                 build_address_of (soft_fmod_node),
+                                 2, arg1, arg2);
          if (type != double_type_node)
            call = convert (type, call);
          return call;
@@ -1659,7 +1634,7 @@ lookup_field (tree *typep, tree name)
       tree save_field;
       int i;
 
-      for (field = TYPE_FIELDS (*typep); field; field = TREE_CHAIN (field))
+      for (field = TYPE_FIELDS (*typep); field; field = DECL_CHAIN (field))
        if (DECL_NAME (field) == name)
          return field;
 
@@ -1758,18 +1733,19 @@ build_field_ref (tree self_value, tree self_class, tree name)
              = build3 (COND_EXPR, TREE_TYPE (field_offset),
                        build2 (EQ_EXPR, boolean_type_node,
                                field_offset, integer_zero_node),
-                       build3 (CALL_EXPR, void_type_node, 
-                               build_address_of (soft_nosuchfield_node),
-                               build_tree_list (NULL_TREE, otable_index), 
-                               NULL_TREE),
+                       build_call_nary (void_type_node, 
+                                        build_address_of (soft_nosuchfield_node),
+                                        1, otable_index),
                        field_offset);
          
          field_offset = fold (convert (sizetype, field_offset));
          self_value = java_check_reference (self_value, check);
          address 
-           = fold_build2 (PLUS_EXPR, 
-                          build_pointer_type (TREE_TYPE (field_decl)),
+           = fold_build2 (POINTER_PLUS_EXPR, 
+                          TREE_TYPE (self_value),
                           self_value, field_offset);
+         address = fold_convert (build_pointer_type (TREE_TYPE (field_decl)),
+                                 address);
          return fold_build1 (INDIRECT_REF, TREE_TYPE (field_decl), address);
        }
 
@@ -1787,7 +1763,8 @@ lookup_label (int pc)
   char buf[32];
   if (pc > highest_label_pc_this_method)
     highest_label_pc_this_method = pc;
-  ASM_GENERATE_INTERNAL_LABEL(buf, "LJpc=", start_label_pc_this_method + pc);
+  targetm.asm_out.generate_internal_label (buf, "LJpc=",
+                                          start_label_pc_this_method + pc);
   name = get_identifier (buf);
   if (IDENTIFIER_LOCAL_VALUE (name))
     return IDENTIFIER_LOCAL_VALUE (name);
@@ -1795,7 +1772,6 @@ lookup_label (int pc)
     {
       /* The type of the address of a label is return_address_type_node. */
       tree decl = create_label_decl (name);
-      LABEL_PC (decl) = pc;
       return pushdecl (decl);
     }
 }
@@ -1808,7 +1784,7 @@ generate_name (void)
 {
   static int l_number = 0;
   char buff [32];
-  ASM_GENERATE_INTERNAL_LABEL(buff, "LJv", l_number);
+  targetm.asm_out.generate_internal_label (buff, "LJv", l_number);
   l_number++;
   return get_identifier (buff);
 }
@@ -1817,16 +1793,22 @@ tree
 create_label_decl (tree name)
 {
   tree decl;
-  decl = build_decl (LABEL_DECL, name, 
+  decl = build_decl (input_location, LABEL_DECL, name, 
                     TREE_TYPE (return_address_type_node));
   DECL_CONTEXT (decl) = current_function_decl;
   DECL_IGNORED_P (decl) = 1;
   return decl;
 }
 
-/* This maps a bytecode offset (PC) to various flags. */
+/* This maps a bytecode offset (PC) to various flags.  */
 char *instruction_bits;
 
+/* 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
+   state at that PC.  We only note type states at basic block
+   boundaries.  */
+VEC(tree, gc) *type_states;
+
 static void
 note_label (int current_pc ATTRIBUTE_UNUSED, int target_pc)
 {
@@ -1894,7 +1876,7 @@ expand_java_switch (tree selector, int default_pc)
   java_add_stmt (switch_expr);
 
   x = build3 (CASE_LABEL_EXPR, void_type_node, NULL_TREE, NULL_TREE,
-             create_artificial_label ());
+             create_artificial_label (input_location));
   append_to_statement_list (x, &SWITCH_BODY (switch_expr));
 
   x = build1 (GOTO_EXPR, void_type_node, lookup_label (default_pc));
@@ -1911,23 +1893,35 @@ expand_java_add_case (tree switch_expr, int match, int target_pc)
   value = build_int_cst (TREE_TYPE (switch_expr), match);
   
   x = build3 (CASE_LABEL_EXPR, void_type_node, value, NULL_TREE,
-             create_artificial_label ());
+             create_artificial_label (input_location));
   append_to_statement_list (x, &SWITCH_BODY (switch_expr));
 
   x = build1 (GOTO_EXPR, void_type_node, lookup_label (target_pc));
   append_to_statement_list (x, &SWITCH_BODY (switch_expr));
 }
 
-static tree
-pop_arguments (tree arg_types)
+static VEC(tree,gc) *
+pop_arguments (tree method_type)
 {
-  if (arg_types == end_params_node)
-    return NULL_TREE;
-  if (TREE_CODE (arg_types) == TREE_LIST)
+  function_args_iterator fnai;
+  tree type;
+  VEC(tree,gc) *args = NULL;
+  int arity;
+
+  FOREACH_FUNCTION_ARGS (method_type, type, fnai)
     {
-      tree tail = pop_arguments (TREE_CHAIN (arg_types));
-      tree type = TREE_VALUE (arg_types);
-      tree arg = pop_value (type);
+      /* XXX: leaky abstraction.  */
+      if (type == void_type_node)
+        break;
+
+      VEC_safe_push (tree, gc, args, type);
+    }
+
+  arity = VEC_length (tree, args);
+
+  while (arity--)
+    {
+      tree arg = pop_value (VEC_index (tree, args, arity));
 
       /* We simply cast each argument to its proper type.  This is
         needed since we lose type information coming out of the
@@ -1939,9 +1933,11 @@ pop_arguments (tree arg_types)
               && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)
               && INTEGRAL_TYPE_P (type))
        arg = convert (integer_type_node, arg);
-      return tree_cons (NULL_TREE, arg, tail);
+
+      VEC_replace (tree, args, arity, arg);
     }
-  gcc_unreachable ();
+
+  return args;
 }
 
 /* Attach to PTR (a block) the declaration found in ENTRY. */
@@ -1957,7 +1953,7 @@ attach_init_test_initialization_flags (void **entry, void *ptr)
       if (TREE_CODE (block) == BIND_EXPR)
         {
          tree body = BIND_EXPR_BODY (block);
-         TREE_CHAIN (ite->value) = BIND_EXPR_VARS (block);
+         DECL_CHAIN (ite->value) = BIND_EXPR_VARS (block);
          BIND_EXPR_VARS (block) = ite->value;
          body = build2 (COMPOUND_EXPR, void_type_node,
                         build1 (DECL_EXPR, void_type_node, ite->value), body);
@@ -1997,10 +1993,9 @@ build_class_init (tree clas, tree expr)
 
   if (always_initialize_class_p)
     {
-      init = build3 (CALL_EXPR, void_type_node,
-                    build_address_of (soft_initclass_node),
-                    build_tree_list (NULL_TREE, build_class_ref (clas)),
-                    NULL_TREE);
+      init = build_call_nary (void_type_node,
+                             build_address_of (soft_initclass_node),
+                             1, build_class_ref (clas));
       TREE_SIDE_EFFECTS (init) = 1;
     }
   else
@@ -2014,26 +2009,19 @@ build_class_init (tree clas, tree expr)
        {
          /* Build a declaration and mark it as a flag used to track
             static class initializations. */
-         decl = build_decl (VAR_DECL, NULL_TREE,
+         decl = build_decl (input_location, VAR_DECL, NULL_TREE,
                             boolean_type_node);
          MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
-         LOCAL_CLASS_INITIALIZATION_FLAG (decl) = 1;
          DECL_CONTEXT (decl) = current_function_decl;
-         DECL_FUNCTION_INIT_TEST_CLASS (decl) = clas;
-         /* Tell the check-init code to ignore this decl when not
-             optimizing class initialization. */
-         if (!STATIC_CLASS_INIT_OPT_P ())
-           DECL_BIT_INDEX (decl) = -1;
          DECL_INITIAL (decl) = boolean_false_node;
          /* Don't emit any symbolic debugging info for this decl.  */
          DECL_IGNORED_P (decl) = 1;      
          *init_test_decl = decl;
        }
 
-      init = build3 (CALL_EXPR, void_type_node,
-                    build_address_of (soft_initclass_node),
-                    build_tree_list (NULL_TREE, build_class_ref (clas)),
-                    NULL_TREE);
+      init = build_call_nary (void_type_node,
+                             build_address_of (soft_initclass_node),
+                             1, build_class_ref (clas));
       TREE_SIDE_EFFECTS (init) = 1;
       init = build3 (COND_EXPR, void_type_node,
                     build2 (EQ_EXPR, boolean_type_node, 
@@ -2071,62 +2059,84 @@ typedef struct
   const char *classname;
   const char *method;
   const char *signature;
+  const char *new_classname;
   const char *new_signature;
   int flags;
-  tree (*rewrite_arglist) (tree arglist);
+  void (*rewrite_arglist) (VEC(tree,gc) **);
 } rewrite_rule;
 
 /* Add __builtin_return_address(0) to the end of an arglist.  */
 
 
-static tree 
-rewrite_arglist_getcaller (tree arglist)
+static void
+rewrite_arglist_getcaller (VEC(tree,gc) **arglist)
 {
   tree retaddr 
-    = (build_function_call_expr 
-       (built_in_decls[BUILT_IN_RETURN_ADDRESS],
-       build_tree_list (NULL_TREE, integer_zero_node)));
-  
-  DECL_INLINE (current_function_decl) = 0;
+    = build_call_expr (built_in_decls[BUILT_IN_RETURN_ADDRESS],
+                      1, integer_zero_node);
 
-  return chainon (arglist, 
-                 tree_cons (NULL_TREE, retaddr, 
-                            NULL_TREE));
+  DECL_UNINLINABLE (current_function_decl) = 1;
+
+  VEC_safe_push (tree, gc, *arglist, retaddr);
 }
 
 /* Add this.class to the end of an arglist.  */
 
-static tree 
-rewrite_arglist_getclass (tree arglist)
+static void
+rewrite_arglist_getclass (VEC(tree,gc) **arglist)
 {
-  return chainon (arglist, 
-                 tree_cons (NULL_TREE, build_class_ref (output_class),
-                            NULL_TREE));
+  VEC_safe_push (tree, gc, *arglist, build_class_ref (output_class));
 }
 
 static rewrite_rule rules[] =
   {{"java.lang.Class", "getClassLoader", "()Ljava/lang/ClassLoader;", 
-    "(Ljava/lang/Class;)Ljava/lang/ClassLoader;", 
+    "java.lang.Class", "(Ljava/lang/Class;)Ljava/lang/ClassLoader;", 
     ACC_FINAL|ACC_PRIVATE, rewrite_arglist_getclass},
+
    {"java.lang.Class", "forName", "(Ljava/lang/String;)Ljava/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},
+
    {"gnu.classpath.VMStackWalker", "getCallingClass", "()Ljava/lang/Class;",
-    "(Lgnu/gcj/RawData;)Ljava/lang/Class;",
+    "gnu.classpath.VMStackWalker", "(Lgnu/gcj/RawData;)Ljava/lang/Class;",
     ACC_FINAL|ACC_PRIVATE|ACC_STATIC, rewrite_arglist_getcaller},
+
    {"gnu.classpath.VMStackWalker", "getCallingClassLoader", 
     "()Ljava/lang/ClassLoader;",
-    "(Lgnu/gcj/RawData;)Ljava/lang/ClassLoader;",
+    "gnu.classpath.VMStackWalker", "(Lgnu/gcj/RawData;)Ljava/lang/ClassLoader;",
     ACC_FINAL|ACC_PRIVATE|ACC_STATIC, rewrite_arglist_getcaller},
 
-   {NULL, NULL, NULL, NULL, 0, NULL}};
+   {"gnu.java.lang.VMCPStringBuilder", "toString", "([CII)Ljava/lang/String;", 
+    "java.lang.String", "([CII)Ljava/lang/String;",
+    ACC_FINAL|ACC_PRIVATE|ACC_STATIC, NULL},
+
+   {NULL, NULL, NULL, NULL, NULL, 0, NULL}};
+
+/* True if this method is special, i.e. it's a private method that
+   should be exported from a DSO.  */
+
+bool
+special_method_p (tree candidate_method)
+{
+  tree context = DECL_NAME (TYPE_NAME (DECL_CONTEXT (candidate_method)));
+  tree method = DECL_NAME (candidate_method);
+  rewrite_rule *p;
+
+  for (p = rules; p->classname; p++)
+    {
+      if (get_identifier (p->classname) == context
+         && get_identifier (p->method) == method)
+       return true;
+    }
+  return false;
+}
 
 /* Scan the rules list for replacements for *METHOD_P and replace the
    args accordingly.  If the rewrite results in an access to a private
    method, update SPECIAL.*/
 
 void
-maybe_rewrite_invocation (tree *method_p, tree *arg_list_p, 
+maybe_rewrite_invocation (tree *method_p, VEC(tree,gc) **arg_list_p, 
                          tree *method_signature_p, tree *special)
 {
   tree context = DECL_NAME (TYPE_NAME (DECL_CONTEXT (*method_p)));
@@ -2141,20 +2151,25 @@ maybe_rewrite_invocation (tree *method_p, tree *arg_list_p,
          if (get_identifier (p->method) == method
              && get_identifier (p->signature) == *method_signature_p)
            {
-             tree maybe_method
-               = lookup_java_method (DECL_CONTEXT (*method_p),
+             tree maybe_method;
+             tree destination_class 
+               = lookup_class (get_identifier (p->new_classname));
+             gcc_assert (destination_class);
+             maybe_method
+               = lookup_java_method (destination_class,
                                      method,
                                      get_identifier (p->new_signature));
              if (! maybe_method && ! flag_verify_invocations)
                {
                  maybe_method
-                   = add_method (DECL_CONTEXT (*method_p), p->flags, 
+                   = add_method (destination_class, p->flags, 
                                  method, get_identifier (p->new_signature));
                  DECL_EXTERNAL (maybe_method) = 1;
                }
              *method_p = maybe_method;
              gcc_assert (*method_p);
-             *arg_list_p = p->rewrite_arglist (*arg_list_p);
+             if (p->rewrite_arglist)
+               p->rewrite_arglist (arg_list_p);
              *method_signature_p = get_identifier (p->new_signature);
              *special = integer_one_node;
 
@@ -2169,7 +2184,7 @@ maybe_rewrite_invocation (tree *method_p, tree *arg_list_p,
 tree
 build_known_method_ref (tree method, tree method_type ATTRIBUTE_UNUSED,
                        tree self_type, tree method_signature ATTRIBUTE_UNUSED,
-                       tree arg_list ATTRIBUTE_UNUSED, tree special)
+                       VEC(tree,gc) *arg_list ATTRIBUTE_UNUSED, tree special)
 {
   tree func;
   if (is_compiled_class (self_type))
@@ -2225,7 +2240,7 @@ build_known_method_ref (tree method, tree method_type ATTRIBUTE_UNUSED,
                    lookup_field (&class_type_node, methods_ident),
                    NULL_TREE);
       for (meth = TYPE_METHODS (self_type);
-          ; meth = TREE_CHAIN (meth))
+          ; meth = DECL_CHAIN (meth))
        {
          if (method == meth)
            break;
@@ -2235,8 +2250,8 @@ build_known_method_ref (tree method, tree method_type ATTRIBUTE_UNUSED,
          method_index++;
        }
       method_index *= int_size_in_bytes (method_type_node);
-      ref = fold_build2 (PLUS_EXPR, method_ptr_type_node,
-                        ref, build_int_cst (NULL_TREE, method_index));
+      ref = fold_build2 (POINTER_PLUS_EXPR, method_ptr_type_node,
+                        ref, size_int (method_index));
       ref = build1 (INDIRECT_REF, method_type_node, ref);
       func = build3 (COMPONENT_REF, nativecode_ptr_type_node,
                     ref, lookup_field (&method_type_node, ncode_ident),
@@ -2246,18 +2261,19 @@ build_known_method_ref (tree method, tree method_type ATTRIBUTE_UNUSED,
 }
 
 tree
-invoke_build_dtable (int is_invoke_interface, tree arg_list)
+invoke_build_dtable (int is_invoke_interface, VEC(tree,gc) *arg_list)
 {
   tree dtable, objectref;
+  tree saved = save_expr (VEC_index (tree, arg_list, 0));
 
-  TREE_VALUE (arg_list) = save_expr (TREE_VALUE (arg_list));
+  VEC_replace (tree, arg_list, 0, saved);
 
   /* If we're dealing with interfaces and if the objectref
      argument is an array then get the dispatch table of the class
      Object rather than the one from the objectref.  */
   objectref = (is_invoke_interface 
-              && is_array_type_p (TREE_TYPE (TREE_VALUE (arg_list)))
-              ? build_class_ref (object_type_node) : TREE_VALUE (arg_list));
+              && is_array_type_p (TREE_TYPE (saved))
+              ? build_class_ref (object_type_node) : saved);
 
   if (dtable_ident == NULL_TREE)
     dtable_ident = get_identifier ("vtable");
@@ -2275,34 +2291,22 @@ invoke_build_dtable (int is_invoke_interface, tree arg_list)
    reused.  */
 
 int
-get_symbol_table_index (tree t, tree special, tree *symbol_table)
+get_symbol_table_index (tree t, tree special,
+                       VEC(method_entry,gc) **symbol_table)
 {
-  int i = 1;
-  tree method_list;
+  method_entry *e;
+  unsigned i;
 
-  if (*symbol_table == NULL_TREE)
-    {
-      *symbol_table = build_tree_list (special, t);
-      return 1;
-    }
-  
-  method_list = *symbol_table;
-  
-  while (1)
-    {
-      tree value = TREE_VALUE (method_list);
-      tree purpose = TREE_PURPOSE (method_list);
-      if (value == t && purpose == special)
-       return i;
-      i++;
-      if (TREE_CHAIN (method_list) == NULL_TREE)
-        break;
-      else
-        method_list = TREE_CHAIN (method_list);
-    }
+  FOR_EACH_VEC_ELT (method_entry, *symbol_table, i, e)
+    if (t == e->method && special == e->special)
+      goto done;
+
+  e = VEC_safe_push (method_entry, gc, *symbol_table, NULL);
+  e->method = t;
+  e->special = special;
 
-  TREE_CHAIN (method_list) = build_tree_list (special, t);
-  return i;
+ done:
+  return i + 1;
 }
 
 tree 
@@ -2340,13 +2344,16 @@ build_invokevirtual (tree dtable, tree method, tree special)
                                   size_int (TARGET_VTABLE_USES_DESCRIPTORS));
     }
 
-  func = fold_build2 (PLUS_EXPR, nativecode_ptr_ptr_type_node, dtable,
-                     convert (nativecode_ptr_ptr_type_node, method_index));
+  func = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (dtable), dtable,
+                     convert (sizetype, method_index));
 
   if (TARGET_VTABLE_USES_DESCRIPTORS)
     func = build1 (NOP_EXPR, nativecode_ptr_type_node, func);
   else
-    func = build1 (INDIRECT_REF, nativecode_ptr_type_node, func);
+    {
+      func = fold_convert (nativecode_ptr_ptr_type_node, func);
+      func = build1 (INDIRECT_REF, nativecode_ptr_type_node, func);
+    }
 
   return func;
 }
@@ -2355,7 +2362,6 @@ static GTY(()) tree class_ident;
 tree
 build_invokeinterface (tree dtable, tree method)
 {
-  tree lookup_arg;
   tree interface;
   tree idx;
 
@@ -2400,13 +2406,9 @@ build_invokeinterface (tree dtable, tree method)
       interface = build_class_ref (interface);
     }
                                                          
-  lookup_arg = tree_cons (NULL_TREE, dtable,
-                         tree_cons (NULL_TREE, interface,
-                                    build_tree_list (NULL_TREE, idx)));
-
-  return build3 (CALL_EXPR, ptr_type_node, 
-                build_address_of (soft_lookupinterfacemethod_node),
-                lookup_arg, NULL_TREE);
+  return build_call_nary (ptr_type_node, 
+                         build_address_of (soft_lookupinterfacemethod_node),
+                         3, dtable, interface, idx);
 }
   
 /* Expand one of the invoke_* opcodes.
@@ -2427,7 +2429,8 @@ expand_invoke (int opcode, int method_ref_index, int nargs ATTRIBUTE_UNUSED)
                           method_ref_index));
   const char *const self_name
     = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (self_type)));
-  tree call, func, method, arg_list, method_type;
+  tree call, func, method, method_type;
+  VEC(tree,gc) *arg_list;
   tree check = NULL_TREE;
 
   tree special = NULL_TREE;
@@ -2534,7 +2537,7 @@ expand_invoke (int opcode, int method_ref_index, int nargs ATTRIBUTE_UNUSED)
         just pop the arguments, push a properly-typed zero, and
         continue.  */
       method_type = get_type_from_signature (method_signature);
-      pop_arguments (TYPE_ARG_TYPES (method_type));
+      pop_arguments (method_type);
       if (opcode != OPCODE_invokestatic) 
        pop_type (self_type);
       method_type = promote_type (TREE_TYPE (method_type));
@@ -2543,7 +2546,7 @@ expand_invoke (int opcode, int method_ref_index, int nargs ATTRIBUTE_UNUSED)
     }
 
   method_type = TREE_TYPE (method);
-  arg_list = pop_arguments (TYPE_ARG_TYPES (method_type));
+  arg_list = pop_arguments (method_type);
   flush_quick_stack ();
 
   maybe_rewrite_invocation (&method, &arg_list, &method_signature,
@@ -2568,8 +2571,8 @@ expand_invoke (int opcode, int method_ref_index, int nargs ATTRIBUTE_UNUSED)
         We do omit the check if we're calling <init>.  */
       /* We use a SAVE_EXPR here to make sure we only evaluate
         the new `self' expression once.  */
-      tree save_arg = save_expr (TREE_VALUE (arg_list));
-      TREE_VALUE (arg_list) = save_arg;
+      tree save_arg = save_expr (VEC_index (tree, arg_list, 0));
+      VEC_replace (tree, arg_list, 0, save_arg);
       check = java_check_reference (save_arg, ! DECL_INIT_P (method));
       func = build_known_method_ref (method, method_type, self_type,
                                     method_signature, arg_list, special);
@@ -2589,8 +2592,7 @@ expand_invoke (int opcode, int method_ref_index, int nargs ATTRIBUTE_UNUSED)
   else
     func = build1 (NOP_EXPR, build_pointer_type (method_type), func);
 
-  call = build3 (CALL_EXPR, TREE_TYPE (method_type),
-                func, arg_list, NULL_TREE);
+  call = build_call_vec (TREE_TYPE (method_type), func, arg_list);
   TREE_SIDE_EFFECTS (call) = 1;
   call = check_for_builtin (method, call);
 
@@ -2615,17 +2617,17 @@ expand_invoke (int opcode, int method_ref_index, int nargs ATTRIBUTE_UNUSED)
 tree
 build_jni_stub (tree method)
 {
-  tree jnifunc, call, args, body, lookup_arg, method_sig, arg_types;
+  tree jnifunc, call, body, method_sig, arg_types;
+  tree jniarg0, jniarg1, jniarg2, jniarg3;
   tree jni_func_type, tem;
   tree env_var, res_var = NULL_TREE, block;
-  tree method_args, res_type;
+  tree method_args;
   tree meth_var;
   tree bind;
-
+  VEC(tree,gc) *args = NULL;
   int args_size = 0;
 
   tree klass = DECL_CONTEXT (method);
-  int from_class = ! CLASS_FROM_SOURCE_P (klass);
   klass = build_class_ref (klass);
 
   gcc_assert (METHOD_NATIVE (method) && flag_jni);
@@ -2633,54 +2635,46 @@ build_jni_stub (tree method)
   DECL_ARTIFICIAL (method) = 1;
   DECL_EXTERNAL (method) = 0;
 
-  env_var = build_decl (VAR_DECL, get_identifier ("env"), ptr_type_node);
+  env_var = build_decl (input_location,
+                       VAR_DECL, get_identifier ("env"), ptr_type_node);
   DECL_CONTEXT (env_var) = method;
 
   if (TREE_TYPE (TREE_TYPE (method)) != void_type_node)
     {
-      res_var = build_decl (VAR_DECL, get_identifier ("res"),
+      res_var = build_decl (input_location, VAR_DECL, get_identifier ("res"),
                            TREE_TYPE (TREE_TYPE (method)));
       DECL_CONTEXT (res_var) = method;
-      TREE_CHAIN (env_var) = res_var;
+      DECL_CHAIN (env_var) = res_var;
     }
 
-  meth_var = build_decl (VAR_DECL, get_identifier ("meth"), ptr_type_node);
-  TREE_STATIC (meth_var) = 1;
-  TREE_PUBLIC (meth_var) = 0;
-  DECL_EXTERNAL (meth_var) = 0;
-  DECL_CONTEXT (meth_var) = method;
-  DECL_ARTIFICIAL (meth_var) = 1;
-  DECL_INITIAL (meth_var) = null_pointer_node;
-  TREE_USED (meth_var) = 1;
-  chainon (env_var, meth_var);
-  build_result_decl (method);
-
-  /* One strange way that the front ends are different is that they
-     store arguments differently.  */
-  if (from_class)
-    method_args = DECL_ARGUMENTS (method);
-  else
-    method_args = BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (method));
+  method_args = DECL_ARGUMENTS (method);
   block = build_block (env_var, NULL_TREE, method_args, NULL_TREE);
   TREE_SIDE_EFFECTS (block) = 1;
-  /* When compiling from source we don't set the type of the block,
-     because that will prevent patch_return from ever being run.  */
-  if (from_class)
-    TREE_TYPE (block) = TREE_TYPE (TREE_TYPE (method));
+  TREE_TYPE (block) = TREE_TYPE (TREE_TYPE (method));
 
   /* Compute the local `env' by calling _Jv_GetJNIEnvNewFrame.  */
   body = build2 (MODIFY_EXPR, ptr_type_node, env_var,
-                build3 (CALL_EXPR, ptr_type_node,
-                        build_address_of (soft_getjnienvnewframe_node),
-                        build_tree_list (NULL_TREE, klass),
-                        NULL_TREE));
-  CAN_COMPLETE_NORMALLY (body) = 1;
+                build_call_nary (ptr_type_node,
+                                 build_address_of (soft_getjnienvnewframe_node),
+                                 1, klass));
+
+  /* The JNIEnv structure is the first argument to the JNI function.  */
+  args_size += int_size_in_bytes (TREE_TYPE (env_var));
+  VEC_safe_push (tree, gc, args, env_var);
+
+  /* For a static method the second argument is the class.  For a
+     non-static method the second argument is `this'; that is already
+     available in the argument list.  */
+  if (METHOD_STATIC (method))
+    {
+      args_size += int_size_in_bytes (TREE_TYPE (klass));
+      VEC_safe_push (tree, gc, args, klass);
+    }
 
   /* All the arguments to this method become arguments to the
      underlying JNI function.  If we had to wrap object arguments in a
      special way, we would do that here.  */
-  args = NULL_TREE;
-  for (tem = method_args; tem != NULL_TREE; tem = TREE_CHAIN (tem))
+  for (tem = method_args; tem != NULL_TREE; tem = DECL_CHAIN (tem))
     {
       int arg_bits = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (tem)));
 #ifdef PARM_BOUNDARY
@@ -2689,41 +2683,27 @@ build_jni_stub (tree method)
 #endif
       args_size += (arg_bits / BITS_PER_UNIT);
 
-      args = tree_cons (NULL_TREE, tem, args);
+      VEC_safe_push (tree, gc, args, tem);
     }
-  args = nreverse (args);
   arg_types = TYPE_ARG_TYPES (TREE_TYPE (method));
 
-  /* For a static method the second argument is the class.  For a
-     non-static method the second argument is `this'; that is already
-     available in the argument list.  */
+  /* Argument types for static methods and the JNIEnv structure.
+     FIXME: Write and use build_function_type_vec to avoid this.  */
   if (METHOD_STATIC (method))
-    {
-      args_size += int_size_in_bytes (TREE_TYPE (klass));
-      args = tree_cons (NULL_TREE, klass, args);
-      arg_types = tree_cons (NULL_TREE, object_ptr_type_node, arg_types);
-    }
-
-  /* The JNIEnv structure is the first argument to the JNI function.  */
-  args_size += int_size_in_bytes (TREE_TYPE (env_var));
-  args = tree_cons (NULL_TREE, env_var, args);
+    arg_types = tree_cons (NULL_TREE, object_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
      function pointer.  _Jv_LookupJNIMethod will throw the appropriate
      exception if this function is not found at runtime.  */
-  tem = build_tree_list (NULL_TREE, build_int_cst (NULL_TREE, args_size));
   method_sig = build_java_signature (TREE_TYPE (method));
-  lookup_arg = tree_cons (NULL_TREE,
-                          build_utf8_ref (unmangle_classname
-                                          (IDENTIFIER_POINTER (method_sig),
-                                           IDENTIFIER_LENGTH (method_sig))), 
-                          tem);
-  tem = DECL_NAME (method);
-  lookup_arg
-    = tree_cons (NULL_TREE, klass,
-                tree_cons (NULL_TREE, build_utf8_ref (tem), lookup_arg));
-  
+  jniarg0 = klass;
+  jniarg1 = build_utf8_ref (DECL_NAME (method));
+  jniarg2 = build_utf8_ref (unmangle_classname
+                           (IDENTIFIER_POINTER (method_sig),
+                            IDENTIFIER_LENGTH (method_sig)));
+  jniarg3 = build_int_cst (NULL_TREE, args_size);
+
   tem = build_function_type (TREE_TYPE (TREE_TYPE (method)), arg_types);
 
 #ifdef MODIFY_JNI_METHOD_CALL
@@ -2732,19 +2712,40 @@ build_jni_stub (tree method)
 
   jni_func_type = build_pointer_type (tem);
 
-  jnifunc = build3 (COND_EXPR, ptr_type_node,
-                   meth_var, meth_var,
-                   build2 (MODIFY_EXPR, ptr_type_node, meth_var,
-                           build3 (CALL_EXPR, ptr_type_node,
-                                   build_address_of
-                                     (soft_lookupjnimethod_node),
-                                   lookup_arg, NULL_TREE)));
+  /* Use the actual function type, rather than a generic pointer type,
+     such that this decl keeps the actual pointer type from being
+     garbage-collected.  If it is, we end up using canonical types
+     with different uids for equivalent function types, and this in
+     turn causes utf8 identifiers and output order to vary.  */
+  meth_var = build_decl (input_location,
+                        VAR_DECL, get_identifier ("meth"), jni_func_type);
+  TREE_STATIC (meth_var) = 1;
+  TREE_PUBLIC (meth_var) = 0;
+  DECL_EXTERNAL (meth_var) = 0;
+  DECL_CONTEXT (meth_var) = method;
+  DECL_ARTIFICIAL (meth_var) = 1;
+  DECL_INITIAL (meth_var) = null_pointer_node;
+  TREE_USED (meth_var) = 1;
+  chainon (env_var, meth_var);
+  build_result_decl (method);
+
+  jnifunc = build3 (COND_EXPR, jni_func_type,
+                   build2 (NE_EXPR, boolean_type_node,
+                           meth_var, build_int_cst (TREE_TYPE (meth_var), 0)),
+                   meth_var,
+                   build2 (MODIFY_EXPR, jni_func_type, meth_var,
+                           build1
+                           (NOP_EXPR, jni_func_type,
+                            build_call_nary (ptr_type_node,
+                                             build_address_of
+                                             (soft_lookupjnimethod_node),
+                                             4,
+                                             jniarg0, jniarg1,
+                                             jniarg2, jniarg3))));
 
   /* Now we make the actual JNI call via the resulting function
      pointer.    */
-  call = build3 (CALL_EXPR, TREE_TYPE (TREE_TYPE (method)),
-                build1 (NOP_EXPR, jni_func_type, jnifunc),
-                args, NULL_TREE);
+  call = build_call_vec (TREE_TYPE (TREE_TYPE (method)), jnifunc, args);
 
   /* If the JNI call returned a result, capture it here.  If we had to
      unwrap JNI object results, we would do that here.  */
@@ -2753,32 +2754,27 @@ build_jni_stub (tree method)
       /* If the call returns an object, it may return a JNI weak
         reference, in which case we must unwrap it.  */
       if (! JPRIMITIVE_TYPE_P (TREE_TYPE (TREE_TYPE (method))))
-       call = build3 (CALL_EXPR, TREE_TYPE (TREE_TYPE (method)),
-                      build_address_of (soft_unwrapjni_node),
-                      build_tree_list (NULL_TREE, call),
-                      NULL_TREE);
+       call = build_call_nary (TREE_TYPE (TREE_TYPE (method)),
+                               build_address_of (soft_unwrapjni_node),
+                               1, call);
       call = build2 (MODIFY_EXPR, TREE_TYPE (TREE_TYPE (method)),
                     res_var, call);
     }
 
   TREE_SIDE_EFFECTS (call) = 1;
-  CAN_COMPLETE_NORMALLY (call) = 1;
 
   body = build2 (COMPOUND_EXPR, void_type_node, body, call);
   TREE_SIDE_EFFECTS (body) = 1;
 
   /* Now free the environment we allocated.  */
-  call = build3 (CALL_EXPR, ptr_type_node,
-                build_address_of (soft_jnipopsystemframe_node),
-                build_tree_list (NULL_TREE, env_var),
-                NULL_TREE);
+  call = build_call_nary (ptr_type_node,
+                         build_address_of (soft_jnipopsystemframe_node),
+                         1, env_var);
   TREE_SIDE_EFFECTS (call) = 1;
-  CAN_COMPLETE_NORMALLY (call) = 1;
   body = build2 (COMPOUND_EXPR, void_type_node, body, call);
   TREE_SIDE_EFFECTS (body) = 1;
 
   /* Finally, do the return.  */
-  res_type = void_type_node;
   if (res_var != NULL_TREE)
     {
       tree drt;
@@ -2795,9 +2791,21 @@ build_jni_stub (tree method)
     }
 
   body = build2 (COMPOUND_EXPR, void_type_node, body,
-                build1 (RETURN_EXPR, res_type, res_var));
+                build1 (RETURN_EXPR, void_type_node, res_var));
   TREE_SIDE_EFFECTS (body) = 1;
   
+  /* Prepend class initialization for static methods reachable from
+     other classes.  */
+  if (METHOD_STATIC (method)
+      && (! METHOD_PRIVATE (method)
+          || INNER_CLASS_P (DECL_CONTEXT (method))))
+    {
+      tree init = build_call_expr (soft_initclass_node, 1, 
+                                  klass);
+      body = build2 (COMPOUND_EXPR, void_type_node, init, body);
+      TREE_SIDE_EFFECTS (body) = 1;
+    }
+
   bind = build3 (BIND_EXPR, void_type_node, BLOCK_VARS (block), 
                 body, block);
   return bind;
@@ -2927,17 +2935,15 @@ expand_java_field_op (int is_static, int is_putting, int field_ref_index)
                            field_ref, new_value);
 
       if (TREE_THIS_VOLATILE (field_decl))
-       java_add_stmt 
-         (build3 
-          (CALL_EXPR, void_type_node,
-           build_address_of (built_in_decls[BUILT_IN_SYNCHRONIZE]),
-           NULL_TREE, NULL_TREE));
+       java_add_stmt
+         (build_call_expr (built_in_decls[BUILT_IN_SYNCHRONIZE], 0));
          
       java_add_stmt (modify_expr);
     }
   else
     {
-      tree temp = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (field_ref));
+      tree temp = build_decl (input_location,
+                             VAR_DECL, NULL_TREE, TREE_TYPE (field_ref));
       java_add_local_var (temp);
 
       if (TREE_THIS_VOLATILE (field_decl))
@@ -2949,21 +2955,18 @@ expand_java_field_op (int is_static, int is_putting, int field_ref_index)
 
       if (TREE_THIS_VOLATILE (field_decl))
        java_add_stmt 
-         (build3 
-          (CALL_EXPR, void_type_node,
-           build_address_of (built_in_decls[BUILT_IN_SYNCHRONIZE]),
-           NULL_TREE, NULL_TREE));
+         (build_call_expr (built_in_decls[BUILT_IN_SYNCHRONIZE], 0));
 
       push_value (temp);
     }      
   TREE_THIS_VOLATILE (field_ref) = TREE_THIS_VOLATILE (field_decl);
 }
 
-void
-load_type_state (tree label)
+static void
+load_type_state (int pc)
 {
   int i;
-  tree vec = LABEL_TYPE_STATE (label);
+  tree vec = VEC_index (tree, type_states, pc);
   int cur_length = TREE_VEC_LENGTH (vec);
   stack_pointer = cur_length - DECL_MAX_LOCALS(current_function_decl);
   for (i = 0; i < cur_length; i++)
@@ -3004,8 +3007,10 @@ note_instructions (JCF *jcf, tree method)
 
   JCF_SEEK (jcf, DECL_CODE_OFFSET (method));
   byte_ops = jcf->read_ptr;
-  instruction_bits = xrealloc (instruction_bits, length + 1);
+  instruction_bits = XRESIZEVAR (char, instruction_bits, length + 1);
   memset (instruction_bits, 0, length + 1);
+  type_states = VEC_alloc (tree, gc, length + 1);
+  VEC_safe_grow_cleared (tree, gc, type_states, length + 1);
 
   /* This pass figures out which PC can be the targets of jumps. */
   for (PC = 0; PC < length;)
@@ -3125,6 +3130,7 @@ expand_byte_code (JCF *jcf, tree method)
   int dead_code_index = -1;
   unsigned char* byte_ops;
   long length = DECL_CODE_LENGTH (method);
+  location_t max_location = input_location;
 
   stack_pointer = 0;
   JCF_SEEK (jcf, DECL_CODE_OFFSET (method));
@@ -3151,6 +3157,8 @@ expand_byte_code (JCF *jcf, tree method)
     return;
 
   promote_arguments ();
+  cache_this_class_ref (method);
+  cache_cpool_data_ref ();
 
   /* Translate bytecodes.  */
   linenumber_pointer = linenumber_table;
@@ -3162,8 +3170,8 @@ expand_byte_code (JCF *jcf, tree method)
           flush_quick_stack ();
          if ((instruction_bits [PC] & BCODE_TARGET) != 0)
            java_add_stmt (build1 (LABEL_EXPR, void_type_node, label));
-         if (LABEL_VERIFIED (label) || PC == 0)
-           load_type_state (label);
+         if ((instruction_bits[PC] & BCODE_VERIFIED) != 0)
+           load_type_state (PC);
        }
 
       if (! (instruction_bits [PC] & BCODE_VERIFIED))
@@ -3209,11 +3217,9 @@ expand_byte_code (JCF *jcf, tree method)
              if (pc == PC)
                {
                  int line = GET_u2 (linenumber_pointer - 2);
-#ifdef USE_MAPPED_LOCATION
-                 input_location = linemap_line_start (&line_table, line, 1);
-#else
-                 input_location.line = line;
-#endif
+                 input_location = linemap_line_start (line_table, line, 1);
+                 if (input_location > max_location)
+                   max_location = input_location;
                  if (!(instruction_bits[PC] & BCODE_HAS_MULTI_LINENUMBERS))
                    break;
                }
@@ -3223,7 +3229,9 @@ expand_byte_code (JCF *jcf, tree method)
       PC = process_jvm_instruction (PC, byte_ops, length);
       maybe_poplevels (PC);
     } /* for */
-  
+
+  uncache_this_class_ref (method);
+
   if (dead_code_index != -1)
     {
       /* We've just reached the end of a region of dead code.  */
@@ -3231,6 +3239,8 @@ expand_byte_code (JCF *jcf, tree method)
        warning (0, "unreachable bytecode from %d to the end of the method", 
                 dead_code_index);
     }
+
+  DECL_FUNCTION_LAST_LINE (method) = max_location;
 }
 
 static void
@@ -3289,6 +3299,7 @@ process_jvm_instruction (int PC, const unsigned char* byte_ops,
   {                                                                    \
     int saw_index = 0;                                                 \
     int index     = OPERAND_VALUE;                                     \
+    (void) saw_index; /* Avoid set but not used warning.  */           \
     build_java_ret                                                     \
       (find_local_variable (index, return_address_type_node, oldpc));  \
   }
@@ -3435,9 +3446,9 @@ process_jvm_instruction (int PC, const unsigned char* byte_ops,
   }
 #define ARRAY_NEW_MULTI()                                      \
   {                                                            \
-    tree class = get_class_constant (current_jcf, IMMEDIATE_u2 );      \
+    tree klass = get_class_constant (current_jcf, IMMEDIATE_u2 );      \
     int  ndims = IMMEDIATE_u1;                                 \
-    expand_java_multianewarray( class, ndims );                        \
+    expand_java_multianewarray( klass, ndims );                        \
   }
 
 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) \
@@ -3705,40 +3716,36 @@ force_evaluation_order (tree node)
          && TREE_CODE (TREE_OPERAND (node, 0)) == CALL_EXPR
          && TREE_CODE (TREE_OPERAND (node, 1)) == SAVE_EXPR)) 
     {
-      tree arg, cmp;
+      tree call, cmp;
+      int i, nargs;
 
-      arg = node;
-      
-      /* Position arg properly, account for wrapped around ctors. */
+      /* Account for wrapped around ctors.  */
       if (TREE_CODE (node) == COMPOUND_EXPR)
-        arg = TREE_OPERAND (node, 0);
-      
-      arg = TREE_OPERAND (arg, 1);
-      
-      /* An empty argument list is ok, just ignore it.  */
-      if (!arg)
-       return node;
+        call = TREE_OPERAND (node, 0);
+      else
+       call = node;
 
-      /* Not having a list of arguments here is an error. */ 
-      gcc_assert (TREE_CODE (arg) == TREE_LIST);
+      nargs = call_expr_nargs (call);
 
       /* This reverses the evaluation order. This is a desired effect. */
-      for (cmp = NULL_TREE; arg; arg = TREE_CHAIN (arg))
+      for (i = 0, cmp = NULL_TREE; i < nargs; i++)
        {
+         tree arg = CALL_EXPR_ARG (call, i);
          /* Promote types smaller than integer.  This is required by
             some ABIs.  */
-         tree type = TREE_TYPE (TREE_VALUE (arg));
+         tree type = TREE_TYPE (arg);
          tree saved;
          if (targetm.calls.promote_prototypes (type)
              && INTEGRAL_TYPE_P (type)
              && INT_CST_LT_UNSIGNED (TYPE_SIZE (type),
                                      TYPE_SIZE (integer_type_node)))
-           TREE_VALUE (arg) = fold_convert (integer_type_node, TREE_VALUE (arg));
+           arg = fold_convert (integer_type_node, arg);
 
-         saved = save_expr (force_evaluation_order (TREE_VALUE (arg)));
+         saved = save_expr (force_evaluation_order (arg));
          cmp = (cmp == NULL_TREE ? saved :
                 build2 (COMPOUND_EXPR, void_type_node, cmp, saved));
-         TREE_VALUE (arg) = saved;
+
+         CALL_EXPR_ARG (call, i) = saved;
        }
       
       if (cmp && TREE_CODE (cmp) == COMPOUND_EXPR)
@@ -3749,7 +3756,6 @@ force_evaluation_order (tree node)
          cmp = build2 (COMPOUND_EXPR, TREE_TYPE (node), cmp, node);
          if (TREE_TYPE (cmp) != void_type_node)
            cmp = save_expr (cmp);
-         CAN_COMPLETE_NORMALLY (cmp) = CAN_COMPLETE_NORMALLY (node);
          TREE_SIDE_EFFECTS (cmp) = 1;
          node = cmp;
        }
@@ -3762,8 +3768,7 @@ force_evaluation_order (tree node)
 tree
 build_java_empty_stmt (void)
 {
-  tree t = build_empty_stmt ();
-  CAN_COMPLETE_NORMALLY (t) = 1;
+  tree t = build_empty_stmt (input_location);
   return t;
 }
 
@@ -3775,7 +3780,7 @@ promote_arguments (void)
   int i;
   tree arg;
   for (arg = DECL_ARGUMENTS (current_function_decl), i = 0;
-       arg != NULL_TREE;  arg = TREE_CHAIN (arg), i++)
+       arg != NULL_TREE;  arg = DECL_CHAIN (arg), i++)
     {
       tree arg_type = TREE_TYPE (arg);
       if (INTEGRAL_TYPE_P (arg_type)
@@ -3791,4 +3796,26 @@ promote_arguments (void)
     }
 }
 
+/* Create a local variable that points to the constant pool.  */
+
+static void
+cache_cpool_data_ref (void)
+{
+  if (optimize)
+    {
+      tree cpool;
+      tree d = build_constant_data_ref (flag_indirect_classes);
+      tree cpool_ptr = build_decl (input_location, VAR_DECL, NULL_TREE, 
+                                  build_pointer_type (TREE_TYPE (d)));
+      java_add_local_var (cpool_ptr);
+      TREE_CONSTANT (cpool_ptr) = 1;
+
+      java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (cpool_ptr), 
+                            cpool_ptr, build_address_of (d)));
+      cpool = build1 (INDIRECT_REF, TREE_TYPE (d), cpool_ptr);
+      TREE_THIS_NOTRAP (cpool) = 1;
+      TYPE_CPOOL_DATA_REF (output_class) = cpool;
+    }
+}
+
 #include "gt-java-expr.h"