OSDN Git Service

Uniquization of constants at the Tree level
[pf3gnuchains/gcc-fork.git] / gcc / java / expr.c
index a64bda8..177a038 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
-   Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+   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.
@@ -42,8 +41,10 @@ The Free Software Foundation is independent of Sun Microsystems, Inc.  */
 #include "parse.h"
 #include "toplev.h"
 #include "except.h"
+#include "tm_p.h"
 #include "ggc.h"
-#include "tree-gimple.h"
+#include "tree-iterator.h"
+#include "gimple.h"
 #include "target.h"
 
 static void flush_quick_stack (void);
@@ -74,11 +75,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);
-#if 0
-static void expand_java_call (int, int);
-static void expand_java_ret (tree); 
-#endif
-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); 
@@ -87,6 +84,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];
 
@@ -301,6 +299,13 @@ push_value (tree value)
       TREE_CHAIN (node) = quick_stack;
       quick_stack = node;
     }
+  /* 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
+     the quick stack.  It is safest to simply always flush, though,
+     since TREE_SIDE_EFFECTS doesn't capture COMPONENT_REF, and for
+     the latter we may need to strip conversions.  */
+  flush_quick_stack ();
 }
 
 /* Pop a type from the type stack.
@@ -415,8 +420,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);
@@ -427,28 +432,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, 
@@ -608,7 +632,7 @@ java_stack_pop (int count)
 {
   while (count > 0)
     {
-      tree type, val;
+      tree type;
 
       gcc_assert (stack_pointer != 0);
 
@@ -620,7 +644,7 @@ java_stack_pop (int count)
 
          type = stack_type_map[stack_pointer - 2];
        }
-      val = pop_value (type);
+      pop_value (type);
       count--;
     }
 }
@@ -635,9 +659,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 ();
@@ -646,7 +669,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, 
@@ -712,11 +735,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);
@@ -795,10 +816,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);
 }
 
@@ -846,9 +877,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);
     }
 
@@ -874,10 +905,11 @@ 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));
+  tree size_exp = fold_convert (sizetype, size_in_bytes (type));
 
   if (!is_array_type_p (TREE_TYPE (array)))
     {
@@ -901,27 +933,45 @@ 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"));
 
   ref = build3 (COMPONENT_REF, TREE_TYPE (data_field),    
                build_java_indirect_ref (array_type, array, 
                                         flag_check_references),
                data_field, NULL_TREE);
-  
-  node = build4 (ARRAY_REF, type, ref, index, NULL_TREE, NULL_TREE);
-  return node;
+
+  /* Take the address of the data field and convert it to a pointer to
+     the element type.  */
+  node = build1 (NOP_EXPR, build_pointer_type (type), build_address_of (ref));
+
+  /* Multiply the index by the size of an element to obtain a byte
+     offset.  Convert the result to a pointer to the element type.  */
+  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 (POINTER_PLUS_EXPR, TREE_TYPE (node), node, index);
+
+  /* Finally, return
+
+    *((&array->data) + index*size_exp)
+
+  */
+  return build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (node)), node);
 }
 
 /* Generate code to throw an ArrayStoreException if OBJECT is not assignable
@@ -991,11 +1041,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;
@@ -1033,20 +1081,13 @@ build_newarray (int atype_value, tree length)
                             host_integerp (length, 0) == INTEGER_CST
                             ? tree_low_cst (length, 0) : -1);
 
-  /* If compiling to native, pass a reference to the primitive type class 
-     and save the runtime some work. However, the bytecode generator
-     expects to find the type_code int here. */
-  if (flag_emit_class_files)
-    type_arg = build_int_cst (NULL_TREE, atype_value);
-  else
-    type_arg = build_class_ref (prim_type);
+  /* Pass a reference to the primitive type class and save the runtime
+     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
@@ -1060,13 +1101,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]'. */
@@ -1088,19 +1128,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;
+
+  VEC_safe_grow (tree, gc, args, 3 + ndim);
+
+  VEC_replace (tree, args, 0, build_class_ref (class_type));
+  VEC_replace (tree, args, 1, build_int_cst (NULL_TREE, ndim));
 
-  for( i = 0; i < ndim; i++ )
-    args = tree_cons (NULL_TREE, pop_value (int_type_node), args);
+  for(i = ndim - 1; i >= 0; i-- )
+    VEC_replace (tree, args, (unsigned)(2 + i), pop_value (int_type_node));
 
-  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, 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
@@ -1120,7 +1162,7 @@ expand_java_arraystore (tree rhs_type_node)
                                 && TYPE_PRECISION (rhs_type_node) <= 32) ? 
                                 int_type_node : rhs_type_node);
   tree index = pop_value (int_type_node);
-  tree array_type, array;
+  tree array_type, array, temp, access;
 
   /* If we're processing an `aaload' we might as well just pick
      `Object'.  */
@@ -1142,14 +1184,31 @@ expand_java_arraystore (tree rhs_type_node)
   index = save_expr (index);
   array = save_expr (array);
 
+  /* We want to perform the bounds check (done by
+     build_java_arrayaccess) before the type check (done by
+     build_java_arraystore_check).  So, we call build_java_arrayaccess
+     -- which returns an ARRAY_REF lvalue -- and we then generate code
+     to stash the address of that lvalue in a temp.  Then we call
+     build_java_arraystore_check, and finally we generate a
+     MODIFY_EXPR to set the array element.  */
+
+  access = build_java_arrayaccess (array, rhs_type_node, index);
+  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),
+                        temp, 
+                        build_fold_addr_expr (access)));
+
   if (TREE_CODE (rhs_type_node) == POINTER_TYPE)
     {
       tree check = build_java_arraystore_check (array, rhs_node);
       java_add_stmt (check);
     }
   
-  array = build_java_arrayaccess (array, rhs_type_node, index);
-  java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (array), array, rhs_node));  
+  java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (access), 
+                        build1 (INDIRECT_REF, TREE_TYPE (access), temp),
+                        rhs_node));  
 }
 
 /* Expand the evaluation of ARRAY[INDEX]. build_java_check_indexed_type makes 
@@ -1210,11 +1269,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. */
@@ -1260,7 +1317,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));
     }
 }
 
@@ -1276,7 +1333,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);
@@ -1311,10 +1368,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
@@ -1327,10 +1383,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
@@ -1409,12 +1464,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;
@@ -1432,11 +1484,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);
 }
 
@@ -1491,12 +1541,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;
 }
 
@@ -1508,7 +1553,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);
@@ -1559,11 +1604,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;
@@ -1723,18 +1766,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);
        }
 
@@ -1760,7 +1804,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);
     }
 }
@@ -1782,16 +1825,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)
 {
@@ -1859,7 +1908,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));
@@ -1876,23 +1925,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
@@ -1904,9 +1965,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. */
@@ -1962,10 +2025,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
@@ -1979,26 +2041,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, 
@@ -2036,35 +2091,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 void
+rewrite_arglist_getcaller (VEC(tree,gc) **arglist)
+{
+  tree retaddr 
+    = build_call_expr (built_in_decls[BUILT_IN_RETURN_ADDRESS],
+                      1, integer_zero_node);
+
+  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},
-   {NULL, NULL, NULL, NULL, 0, NULL}};
+
+   {"gnu.classpath.VMStackWalker", "getCallingClass", "()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;",
+    "gnu.classpath.VMStackWalker", "(Lgnu/gcj/RawData;)Ljava/lang/ClassLoader;",
+    ACC_FINAL|ACC_PRIVATE|ACC_STATIC, rewrite_arglist_getcaller},
+
+   {"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)));
@@ -2079,20 +2183,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;
 
@@ -2107,7 +2216,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))
@@ -2173,8 +2282,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),
@@ -2184,18 +2293,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");
@@ -2278,13 +2388,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;
 }
@@ -2293,7 +2406,6 @@ static GTY(()) tree class_ident;
 tree
 build_invokeinterface (tree dtable, tree method)
 {
-  tree lookup_arg;
   tree interface;
   tree idx;
 
@@ -2338,13 +2450,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.
@@ -2365,7 +2473,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;
@@ -2472,7 +2581,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));
@@ -2481,7 +2590,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,
@@ -2506,8 +2615,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);
@@ -2527,8 +2636,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);
 
@@ -2553,17 +2661,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);
@@ -2571,53 +2679,45 @@ 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;
     }
 
-  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))
     {
       int arg_bits = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (tem)));
@@ -2627,41 +2727,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
@@ -2670,19 +2756,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.  */
@@ -2691,32 +2798,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;
@@ -2733,9 +2835,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;
@@ -2837,7 +2951,13 @@ expand_java_field_op (int is_static, int is_putting, int field_ref_index)
   field_ref = build_field_ref (field_ref, self_type, field_name);
   if (is_static
       && ! flag_indirect_dispatch)
-    field_ref = build_class_init (self_type, field_ref);
+    {
+      tree context = DECL_CONTEXT (field_ref);
+      if (context != self_type && CLASS_INTERFACE (TYPE_NAME (context)))
+       field_ref = build_class_init (context, field_ref);
+      else
+       field_ref = build_class_init (self_type, field_ref);
+    }
   if (is_putting)
     {
       flush_quick_stack ();
@@ -2846,21 +2966,10 @@ expand_java_field_op (int is_static, int is_putting, int field_ref_index)
          if (DECL_CONTEXT (field_decl) != current_class)
             error ("assignment to final field %q+D not in field's class",
                    field_decl);
-         else if (FIELD_STATIC (field_decl))
-           {
-             if (!DECL_CLINIT_P (current_function_decl))
-               warning (0, "assignment to final static field %q+D not in "
-                         "class initializer",
-                         field_decl);
-           }
-         else
-           {
-             tree cfndecl_name = DECL_NAME (current_function_decl);
-             if (! DECL_CONSTRUCTOR_P (current_function_decl)
-                 && !ID_FINIT_P (cfndecl_name))
-                warning (0, "assignment to final field %q+D not in constructor",
-                        field_decl);
-           }
+         /* We used to check for assignments to final fields not
+            occurring in the class initializer or in a constructor
+            here.  However, this constraint doesn't seem to be
+            enforced by the JVM.  */
        }      
 
       if (TREE_THIS_VOLATILE (field_decl))
@@ -2870,17 +2979,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))
@@ -2892,21 +2999,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++)
@@ -2947,8 +3051,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;)
@@ -3068,6 +3174,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));
@@ -3094,6 +3201,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;
@@ -3105,8 +3214,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))
@@ -3152,11 +3261,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;
                }
@@ -3166,7 +3273,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.  */
@@ -3174,6 +3283,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
@@ -3232,6 +3343,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));  \
   }
@@ -3378,9 +3490,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) \
@@ -3644,45 +3756,40 @@ force_evaluation_order (tree node)
   if (flag_syntax_only)
     return node;
   if (TREE_CODE (node) == CALL_EXPR
-      || TREE_CODE (node) == NEW_CLASS_EXPR
       || (TREE_CODE (node) == COMPOUND_EXPR
          && 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)
@@ -3693,7 +3800,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;
        }
@@ -3701,94 +3807,12 @@ force_evaluation_order (tree node)
   return node;
 }
 
-/* EXPR_WITH_FILE_LOCATION are used to keep track of the exact
-   location where an expression or an identifier were encountered. It
-   is necessary for languages where the frontend parser will handle
-   recursively more than one file (Java is one of them).  */
-
-tree
-build_expr_wfl (tree node,
-#ifdef USE_MAPPED_LOCATION
-               source_location location
-#else
-               const char *file, int line, int col
-#endif
-)
-{
-  tree wfl;
-
-#ifdef USE_MAPPED_LOCATION
-  wfl = make_node (EXPR_WITH_FILE_LOCATION);
-  SET_EXPR_LOCATION (wfl, location);
-#else
-  static const char *last_file = 0;
-  static tree last_filenode = NULL_TREE;
-
-  wfl = make_node (EXPR_WITH_FILE_LOCATION);
-
-  EXPR_WFL_SET_LINECOL (wfl, line, col);
-  if (file != last_file)
-    {
-      last_file = file;
-      last_filenode = file ? get_identifier (file) : NULL_TREE;
-    }
-  EXPR_WFL_FILENAME_NODE (wfl) = last_filenode;
-#endif
-  EXPR_WFL_NODE (wfl) = node;
-  if (node)
-    {
-      if (!TYPE_P (node))
-       TREE_SIDE_EFFECTS (wfl) = TREE_SIDE_EFFECTS (node);
-      TREE_TYPE (wfl) = TREE_TYPE (node);
-    }
-
-  return wfl;
-}
-
-#ifdef USE_MAPPED_LOCATION
-tree
-expr_add_location (tree node, source_location location, bool statement)
-{
-  tree wfl;
-#if 0
-  /* FIXME. This optimization causes failures in code that expects an
-     EXPR_WITH_FILE_LOCATION.  E.g. in resolve_qualified_expression_name. */
-  if (node && ! (statement && flag_emit_class_files))
-    {
-      source_location node_loc = EXPR_LOCATION (node);
-      if (node_loc == location || location == UNKNOWN_LOCATION)
-       return node;
-      if (node_loc == UNKNOWN_LOCATION
-         && IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (node))))
-       {
-         SET_EXPR_LOCATION (node, location);
-         return node;
-       }
-    }
-#endif
-  wfl = make_node (EXPR_WITH_FILE_LOCATION);
-  SET_EXPR_LOCATION (wfl, location);
-  EXPR_WFL_NODE (wfl) = node;
-  if (statement && debug_info_level != DINFO_LEVEL_NONE)
-    EXPR_WFL_EMIT_LINE_NOTE (wfl) = 1;
-  if (node)
-    {
-      if (!TYPE_P (node))
-       TREE_SIDE_EFFECTS (wfl) = TREE_SIDE_EFFECTS (node);
-      TREE_TYPE (wfl) = TREE_TYPE (node);
-    }
-
-  return wfl;
-}
-#endif
-
 /* Build a node to represent empty statements and blocks. */
 
 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;
 }
 
@@ -3816,4 +3840,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"