OSDN Git Service

* config/m68k/m68k.c (m68k_rtx_costs): Adjust mul/div costs for
[pf3gnuchains/gcc-fork.git] / gcc / tree-inline.c
index 46ea052..8893b26 100644 (file)
@@ -1,26 +1,28 @@
 /* Control and data flow functions for trees.
-   Copyright 2001, 2002 Free Software Foundation, Inc.
+   Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
    Contributed by Alexandre Oliva <aoliva@redhat.com>
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
+GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2, or (at your option)
 any later version.
 
-GNU CC is distributed in the hope that it will be useful,
+GCC is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
+along with GCC; see the file COPYING.  If not, write to
 the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "toplev.h"
 #include "tree.h"
 #include "tree-inline.h"
@@ -35,14 +37,20 @@ Boston, MA 02111-1307, USA.  */
 #include "hashtab.h"
 #include "splay-tree.h"
 #include "langhooks.h"
+#include "cgraph.h"
 
 /* This should be eventually be generalized to other languages, but
    this would require a shared function-as-trees infrastructure.  */
-#include "c-common.h" 
+#ifndef INLINER_FOR_JAVA
+#include "c-common.h"
+#else /* INLINER_FOR_JAVA */
+#include "parse.h"
+#include "java-tree.h"
+#endif /* INLINER_FOR_JAVA */
 
 /* 0 if we should not perform inlining.
-   1 if we should expand functions calls inline at the tree level.  
-   2 if we should consider *all* functions to be inline 
+   1 if we should expand functions calls inline at the tree level.
+   2 if we should consider *all* functions to be inline
    candidates.  */
 
 int flag_inline_trees = 0;
@@ -83,13 +91,11 @@ typedef struct inline_data
   /* Nonzero if we are currently within the cleanup for a
      TARGET_EXPR.  */
   int in_target_cleanup_p;
-  /* A stack of the TARGET_EXPRs that we are currently processing.  */
-  varray_type target_exprs;
   /* A list of the functions current function has inlined.  */
   varray_type inlined_fns;
-  /* The approximate number of statements we have inlined in the
+  /* The approximate number of instructions we have inlined in the
      current call stack.  */
-  int inlined_stmts;
+  int inlined_insns;
   /* We use the same mechanism to build clones that we do to perform
      inlining.  However, there are a few places where we need to
      distinguish between those two situations.  This flag is true if
@@ -98,32 +104,39 @@ typedef struct inline_data
   /* Hash table used to prevent walk_tree from visiting the same node
      umpteen million times.  */
   htab_t tree_pruner;
+  /* Decl of function we are inlining into.  */
+  tree decl;
+  tree current_decl;
 } inline_data;
 
 /* Prototypes.  */
 
-static tree initialize_inlined_parameters PARAMS ((inline_data *, tree, tree));
-static tree declare_return_variable PARAMS ((inline_data *, tree *));
-static tree copy_body_r PARAMS ((tree *, int *, void *));
-static tree copy_body PARAMS ((inline_data *));
-static tree expand_call_inline PARAMS ((tree *, int *, void *));
-static void expand_calls_inline PARAMS ((tree *, inline_data *));
-static int inlinable_function_p PARAMS ((tree, inline_data *));
-static tree remap_decl PARAMS ((tree, inline_data *));
-static void remap_block PARAMS ((tree, tree, inline_data *));
-static void copy_scope_stmt PARAMS ((tree *, int *, inline_data *));
-
-/* The approximate number of instructions per statement.  This number
-   need not be particularly accurate; it is used only to make
-   decisions about when a function is too big to inline.  */
-#define INSNS_PER_STMT (10)
+static tree declare_return_variable (inline_data *, tree, tree *);
+static tree copy_body_r (tree *, int *, void *);
+static tree copy_body (inline_data *);
+static tree expand_call_inline (tree *, int *, void *);
+static void expand_calls_inline (tree *, inline_data *);
+static bool inlinable_function_p (tree);
+static int limits_allow_inlining (tree, inline_data *);
+static tree remap_decl (tree, inline_data *);
+#ifndef INLINER_FOR_JAVA
+static tree initialize_inlined_parameters (inline_data *, tree, tree);
+static void remap_block (tree, tree, inline_data *);
+static void copy_scope_stmt (tree *, int *, inline_data *);
+#else /* INLINER_FOR_JAVA */
+static tree initialize_inlined_parameters (inline_data *, tree, tree, tree);
+static void remap_block (tree *, tree, inline_data *);
+static tree add_stmt_to_compound (tree, tree, tree);
+#endif /* INLINER_FOR_JAVA */
+static tree find_alloca_call_1 (tree *, int *, void *);
+static tree find_alloca_call (tree);
+static tree find_builtin_longjmp_call_1 (tree *, int *, void *);
+static tree find_builtin_longjmp_call (tree);
 
 /* Remap DECL during the copying of the BLOCK tree for the function.  */
 
 static tree
-remap_decl (decl, id)
-     tree decl;
-     inline_data *id;
+remap_decl (tree decl, inline_data *id)
 {
   splay_tree_node n;
   tree fn;
@@ -158,6 +171,7 @@ remap_decl (decl, id)
                     copy_body_r, id, NULL);
        }
 
+#ifndef INLINER_FOR_JAVA
       if (! DECL_NAME (t) && TREE_TYPE (t)
          && (*lang_hooks.tree_inlining.anon_aggr_type_p) (TREE_TYPE (t)))
        {
@@ -166,7 +180,7 @@ remap_decl (decl, id)
             DECL_ANON_UNION_ELEMS.  */
          tree members = NULL;
          tree src;
-         
+
          for (src = DECL_ANON_UNION_ELEMS (t); src;
               src = TREE_CHAIN (src))
            {
@@ -178,7 +192,8 @@ remap_decl (decl, id)
            }
          DECL_ANON_UNION_ELEMS (t) = nreverse (members);
        }
-      
+#endif /* not INLINER_FOR_JAVA */
+
       /* Remember it, so that if we encounter this local entity
         again we can reuse this copy.  */
       n = splay_tree_insert (id->decl_map,
@@ -189,17 +204,24 @@ remap_decl (decl, id)
   return (tree) n->value;
 }
 
+#ifndef INLINER_FOR_JAVA
 /* Copy the SCOPE_STMT_BLOCK associated with SCOPE_STMT to contain
    remapped versions of the variables therein.  And hook the new block
    into the block-tree.  If non-NULL, the DECLS are declarations to
    add to use instead of the BLOCK_VARS in the old block.  */
+#else /* INLINER_FOR_JAVA */
+/* Copy the BLOCK to contain remapped versions of the variables
+   therein.  And hook the new block into the block-tree.  */
+#endif /* INLINER_FOR_JAVA */
 
 static void
-remap_block (scope_stmt, decls, id)
-     tree scope_stmt;
-     tree decls;
-     inline_data *id;
+#ifndef INLINER_FOR_JAVA
+remap_block (tree scope_stmt, tree decls, inline_data *id)
+#else /* INLINER_FOR_JAVA */
+remap_block (tree *block, tree decls, inline_data *id)
+#endif /* INLINER_FOR_JAVA */
 {
+#ifndef INLINER_FOR_JAVA
   /* We cannot do this in the cleanup for a TARGET_EXPR since we do
      not know whether or not expand_expr will actually write out the
      code we put there.  If it does not, then we'll have more BLOCKs
@@ -289,15 +311,76 @@ remap_block (scope_stmt, decls, id)
        abort ();
       SCOPE_STMT_BLOCK (scope_stmt) = (tree) n->value;
     }
+#else /* INLINER_FOR_JAVA */
+  tree old_block;
+  tree new_block;
+  tree old_var;
+  tree fn;
+
+  /* Make the new block.  */
+  old_block = *block;
+  new_block = make_node (BLOCK);
+  TREE_USED (new_block) = TREE_USED (old_block);
+  BLOCK_ABSTRACT_ORIGIN (new_block) = old_block;
+  BLOCK_SUBBLOCKS (new_block) = BLOCK_SUBBLOCKS (old_block);
+  TREE_SIDE_EFFECTS (new_block) = TREE_SIDE_EFFECTS (old_block);
+  TREE_TYPE (new_block) = TREE_TYPE (old_block);
+  *block = new_block;
+
+  /* Remap its variables.  */
+  for (old_var = decls ? decls : BLOCK_VARS (old_block);
+       old_var;
+       old_var = TREE_CHAIN (old_var))
+    {
+      tree new_var;
+
+      /* All local class initialization flags go in the outermost
+        scope.  */
+      if (LOCAL_CLASS_INITIALIZATION_FLAG_P (old_var))
+       {
+         /* We may already have one.  */
+         if (! splay_tree_lookup (id->decl_map, (splay_tree_key) old_var))
+           {
+             tree outermost_block;
+             new_var = remap_decl (old_var, id);
+             DECL_ABSTRACT_ORIGIN (new_var) = NULL;
+             outermost_block = DECL_SAVED_TREE (current_function_decl);
+             TREE_CHAIN (new_var) = BLOCK_VARS (outermost_block);
+             BLOCK_VARS (outermost_block) = new_var;
+           }
+         continue;
+       }
+
+      /* Remap the variable.  */
+      new_var = remap_decl (old_var, id);
+      /* If we didn't remap this variable, so we can't mess with
+        its TREE_CHAIN.  If we remapped this variable to
+        something other than a declaration (say, if we mapped it
+        to a constant), then we must similarly omit any mention
+        of it here.  */
+      if (!new_var || !DECL_P (new_var))
+       ;
+      else
+       {
+         TREE_CHAIN (new_var) = BLOCK_VARS (new_block);
+         BLOCK_VARS (new_block) = new_var;
+       }
+    }
+  /* We put the BLOCK_VARS in reverse order; fix that now.  */
+  BLOCK_VARS (new_block) = nreverse (BLOCK_VARS (new_block));
+  fn = VARRAY_TREE (id->fns, 0);
+  /* Remember the remapped block.  */
+  splay_tree_insert (id->decl_map,
+                    (splay_tree_key) old_block,
+                    (splay_tree_value) new_block);
+#endif /* INLINER_FOR_JAVA */
 }
 
+#ifndef INLINER_FOR_JAVA
 /* Copy the SCOPE_STMT pointed to by TP.  */
 
 static void
-copy_scope_stmt (tp, walk_subtrees, id)
-     tree *tp;
-     int *walk_subtrees;
-     inline_data *id;
+copy_scope_stmt (tree *tp, int *walk_subtrees, inline_data *id)
 {
   tree block;
 
@@ -314,15 +397,12 @@ copy_scope_stmt (tp, walk_subtrees, id)
   /* Remap the associated block.  */
   remap_block (*tp, NULL_TREE, id);
 }
+#endif /* not INLINER_FOR_JAVA */
 
 /* Called from copy_body via walk_tree.  DATA is really an
    `inline_data *'.  */
-
 static tree
-copy_body_r (tp, walk_subtrees, data)
-     tree *tp;
-     int *walk_subtrees;
-     void *data;
+copy_body_r (tree *tp, int *walk_subtrees, void *data)
 {
   inline_data* id;
   tree fn;
@@ -340,29 +420,53 @@ copy_body_r (tp, walk_subtrees, data)
       abort ();
 #endif
 
+#ifdef INLINER_FOR_JAVA
+  if (TREE_CODE (*tp) == BLOCK)
+    remap_block (tp, NULL_TREE, id);
+#endif
+
   /* If this is a RETURN_STMT, change it into an EXPR_STMT and a
      GOTO_STMT with the RET_LABEL as its target.  */
+#ifndef INLINER_FOR_JAVA
   if (TREE_CODE (*tp) == RETURN_STMT && id->ret_label)
+#else /* INLINER_FOR_JAVA */
+  if (TREE_CODE (*tp) == RETURN_EXPR && id->ret_label)
+#endif /* INLINER_FOR_JAVA */
     {
       tree return_stmt = *tp;
       tree goto_stmt;
 
       /* Build the GOTO_STMT.  */
+#ifndef INLINER_FOR_JAVA
       goto_stmt = build_stmt (GOTO_STMT, id->ret_label);
       TREE_CHAIN (goto_stmt) = TREE_CHAIN (return_stmt);
       GOTO_FAKE_P (goto_stmt) = 1;
+#else /* INLINER_FOR_JAVA */
+      tree assignment = TREE_OPERAND (return_stmt, 0);
+      goto_stmt = build1 (GOTO_EXPR, void_type_node, id->ret_label);
+      TREE_SIDE_EFFECTS (goto_stmt) = 1;
+#endif /* INLINER_FOR_JAVA */
 
       /* If we're returning something, just turn that into an
         assignment into the equivalent of the original
         RESULT_DECL.  */
-      if (RETURN_EXPR (return_stmt))
+#ifndef INLINER_FOR_JAVA
+      if (RETURN_STMT_EXPR (return_stmt))
        {
          *tp = build_stmt (EXPR_STMT,
-                           RETURN_EXPR (return_stmt));
+                           RETURN_STMT_EXPR (return_stmt));
          STMT_IS_FULL_EXPR_P (*tp) = 1;
          /* And then jump to the end of the function.  */
          TREE_CHAIN (*tp) = goto_stmt;
        }
+#else /* INLINER_FOR_JAVA */
+      if (assignment)
+       {
+         copy_body_r (&assignment, walk_subtrees, data);
+         *tp = build (COMPOUND_EXPR, void_type_node, assignment, goto_stmt);
+         TREE_SIDE_EFFECTS (*tp) = 1;
+       }
+#endif /* INLINER_FOR_JAVA */
       /* If we're not returning anything just do the jump.  */
       else
        *tp = goto_stmt;
@@ -394,27 +498,43 @@ copy_body_r (tp, walk_subtrees, data)
   else if (TREE_CODE (*tp) == UNSAVE_EXPR)
     /* UNSAVE_EXPRs should not be generated until expansion time.  */
     abort ();
+#ifndef INLINER_FOR_JAVA
   /* For a SCOPE_STMT, we must copy the associated block so that we
      can write out debugging information for the inlined variables.  */
   else if (TREE_CODE (*tp) == SCOPE_STMT && !id->in_target_cleanup_p)
     copy_scope_stmt (tp, walk_subtrees, id);
+#else /* INLINER_FOR_JAVA */
+  else if (TREE_CODE (*tp) == LABELED_BLOCK_EXPR)
+    {
+      /* We need a new copy of this labeled block; the EXIT_BLOCK_EXPR
+         will refer to it, so save a copy ready for remapping.  We
+         save it in the decl_map, although it isn't a decl.  */
+      tree new_block = copy_node (*tp);
+      splay_tree_insert (id->decl_map,
+                        (splay_tree_key) *tp,
+                        (splay_tree_value) new_block);
+      *tp = new_block;
+    }
+  else if (TREE_CODE (*tp) == EXIT_BLOCK_EXPR)
+    {
+      splay_tree_node n
+       = splay_tree_lookup (id->decl_map,
+                            (splay_tree_key) TREE_OPERAND (*tp, 0));
+      /* We _must_ have seen the enclosing LABELED_BLOCK_EXPR.  */
+      if (! n)
+       abort ();
+      *tp = copy_node (*tp);
+      TREE_OPERAND (*tp, 0) = (tree) n->value;
+    }
+#endif /* INLINER_FOR_JAVA */
   /* Otherwise, just copy the node.  Note that copy_tree_r already
      knows not to copy VAR_DECLs, etc., so this is safe.  */
   else
     {
-      copy_tree_r (tp, walk_subtrees, NULL);
-
-      /* The copied TARGET_EXPR has never been expanded, even if the
-        original node was expanded already.  */
-      if (TREE_CODE (*tp) == TARGET_EXPR && TREE_OPERAND (*tp, 3))
-       {
-         TREE_OPERAND (*tp, 1) = TREE_OPERAND (*tp, 3);
-         TREE_OPERAND (*tp, 3) = NULL_TREE;
-       }
-      else if (TREE_CODE (*tp) == MODIFY_EXPR
-              && TREE_OPERAND (*tp, 0) == TREE_OPERAND (*tp, 1)
-              && ((*lang_hooks.tree_inlining.auto_var_in_fn_p)
-                  (TREE_OPERAND (*tp, 0), fn)))
+      if (TREE_CODE (*tp) == MODIFY_EXPR
+         && TREE_OPERAND (*tp, 0) == TREE_OPERAND (*tp, 1)
+         && ((*lang_hooks.tree_inlining.auto_var_in_fn_p)
+             (TREE_OPERAND (*tp, 0), fn)))
        {
          /* Some assignments VAR = VAR; don't generate any rtl code
             and thus don't count as variable modification.  Avoid
@@ -428,9 +548,43 @@ copy_body_r (tp, walk_subtrees, data)
              value = (tree) n->value;
              STRIP_TYPE_NOPS (value);
              if (TREE_CONSTANT (value) || TREE_READONLY_DECL_P (value))
-               *tp = value;
+               {
+                 *tp = value;
+                 return copy_body_r (tp, walk_subtrees, data);
+               }
+           }
+       }
+      else if (TREE_CODE (*tp) == ADDR_EXPR
+              && ((*lang_hooks.tree_inlining.auto_var_in_fn_p)
+                  (TREE_OPERAND (*tp, 0), fn)))
+       {
+         /* Get rid of &* from inline substitutions.  It can occur when
+            someone takes the address of a parm or return slot passed by
+            invisible reference.  */
+         tree decl = TREE_OPERAND (*tp, 0), value;
+         splay_tree_node n;
+
+         n = splay_tree_lookup (id->decl_map, (splay_tree_key) decl);
+         if (n)
+           {
+             value = (tree) n->value;
+             if (TREE_CODE (value) == INDIRECT_REF)
+               {
+                 *tp = convert (TREE_TYPE (*tp), TREE_OPERAND (value, 0));
+                 return copy_body_r (tp, walk_subtrees, data);
+               }
            }
        }
+
+      copy_tree_r (tp, walk_subtrees, NULL);
+
+      /* The copied TARGET_EXPR has never been expanded, even if the
+        original node was expanded already.  */
+      if (TREE_CODE (*tp) == TARGET_EXPR && TREE_OPERAND (*tp, 3))
+       {
+         TREE_OPERAND (*tp, 1) = TREE_OPERAND (*tp, 3);
+         TREE_OPERAND (*tp, 3) = NULL_TREE;
+       }
     }
 
   /* Keep iterating.  */
@@ -441,8 +595,7 @@ copy_body_r (tp, walk_subtrees, data)
    another function.  */
 
 static tree
-copy_body (id)
-     inline_data *id;
+copy_body (inline_data *id)
 {
   tree body;
 
@@ -456,15 +609,19 @@ copy_body (id)
    top of the stack in ID from the ARGS (presented as a TREE_LIST).  */
 
 static tree
-initialize_inlined_parameters (id, args, fn)
-     inline_data *id;
-     tree args;
-     tree fn;
+#ifndef INLINER_FOR_JAVA
+initialize_inlined_parameters (inline_data *id, tree args, tree fn)
+#else /* INLINER_FOR_JAVA */
+initialize_inlined_parameters (inline_data *id, tree args, tree fn, tree block)
+#endif /* INLINER_FOR_JAVA */
 {
   tree init_stmts;
   tree parms;
   tree a;
   tree p;
+#ifdef INLINER_FOR_JAVA
+  tree vars = NULL_TREE;
+#endif /* INLINER_FOR_JAVA */
 
   /* Figure out what the parameters are.  */
   parms = DECL_ARGUMENTS (fn);
@@ -477,10 +634,13 @@ initialize_inlined_parameters (id, args, fn)
   for (p = parms, a = args; p;
        a = a ? TREE_CHAIN (a) : a, p = TREE_CHAIN (p))
     {
+#ifndef INLINER_FOR_JAVA
       tree init_stmt;
+      tree cleanup;
+#endif /* not INLINER_FOR_JAVA */
       tree var;
       tree value;
-      tree cleanup;
+      tree var_sub;
 
       /* Find the initializer.  */
       value = (*lang_hooks.tree_inlining.convert_parm_for_inlining)
@@ -509,6 +669,10 @@ initialize_inlined_parameters (id, args, fn)
              if (DECL_P (value))
                value = build1 (NOP_EXPR, TREE_TYPE (value), value);
 
+             /* If this is a constant, make sure it has the right type.  */
+             else if (TREE_TYPE (value) != TREE_TYPE (p))
+               value = fold (build1 (NOP_EXPR, TREE_TYPE (p), value));
+
              splay_tree_insert (id->decl_map,
                                 (splay_tree_key) p,
                                 (splay_tree_value) value);
@@ -518,17 +682,33 @@ initialize_inlined_parameters (id, args, fn)
 
       /* Make an equivalent VAR_DECL.  */
       var = copy_decl_for_inlining (p, fn, VARRAY_TREE (id->fns, 0));
+
+      /* See if the frontend wants to pass this by invisible reference.  If
+        so, our new VAR_DECL will have REFERENCE_TYPE, and we need to
+        replace uses of the PARM_DECL with dereferences.  */
+      if (TREE_TYPE (var) != TREE_TYPE (p)
+         && POINTER_TYPE_P (TREE_TYPE (var))
+         && TREE_TYPE (TREE_TYPE (var)) == TREE_TYPE (p))
+       var_sub = build1 (INDIRECT_REF, TREE_TYPE (p), var);
+      else
+       var_sub = var;
+
       /* Register the VAR_DECL as the equivalent for the PARM_DECL;
         that way, when the PARM_DECL is encountered, it will be
         automatically replaced by the VAR_DECL.  */
       splay_tree_insert (id->decl_map,
                         (splay_tree_key) p,
-                        (splay_tree_value) var);
+                        (splay_tree_value) var_sub);
 
       /* Declare this new variable.  */
+#ifndef INLINER_FOR_JAVA
       init_stmt = build_stmt (DECL_STMT, var);
       TREE_CHAIN (init_stmt) = init_stmts;
       init_stmts = init_stmt;
+#else /* INLINER_FOR_JAVA */
+      TREE_CHAIN (var) = vars;
+      vars = var;
+#endif /* INLINER_FOR_JAVA */
 
       /* Initialize this VAR_DECL from the equivalent argument.  If
         the argument is an object, created via a constructor or copy,
@@ -536,6 +716,7 @@ initialize_inlined_parameters (id, args, fn)
         representing the argument will be bound to VAR, and the
         object will be constructed in VAR.  */
       if (! TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (p)))
+#ifndef INLINER_FOR_JAVA
        DECL_INITIAL (var) = value;
       else
        {
@@ -562,8 +743,8 @@ initialize_inlined_parameters (id, args, fn)
        }
 
       /* See if we need to clean up the declaration.  */
-      cleanup = maybe_build_cleanup (var);
-      if (cleanup) 
+      cleanup = (*lang_hooks.maybe_build_cleanup) (var);
+      if (cleanup)
        {
          tree cleanup_stmt;
          /* Build the cleanup statement.  */
@@ -573,8 +754,23 @@ initialize_inlined_parameters (id, args, fn)
          TREE_CHAIN (cleanup_stmt) = init_stmts;
          init_stmts = cleanup_stmt;
        }
+#else /* INLINER_FOR_JAVA */
+       {
+         tree assignment = build (MODIFY_EXPR, TREE_TYPE (p), var, value);
+         init_stmts = add_stmt_to_compound (init_stmts, TREE_TYPE (p),
+                                            assignment);
+       }
+      else
+       {
+         /* Java objects don't ever need constructing when being
+             passed as arguments because only call by reference is
+             supported.  */
+         abort ();
+       }
+#endif /* INLINER_FOR_JAVA */
     }
 
+#ifndef INLINER_FOR_JAVA
   /* Evaluate trailing arguments.  */
   for (; a; a = TREE_CHAIN (a))
     {
@@ -592,6 +788,10 @@ initialize_inlined_parameters (id, args, fn)
   /* The initialization statements have been built up in reverse
      order.  Straighten them out now.  */
   return nreverse (init_stmts);
+#else /* INLINER_FOR_JAVA */
+  BLOCK_VARS (block) = nreverse (vars);
+  return init_stmts;
+#endif /* INLINER_FOR_JAVA */
 }
 
 /* Declare a return variable to replace the RESULT_DECL for the
@@ -599,27 +799,39 @@ initialize_inlined_parameters (id, args, fn)
    The USE_STMT is filled in to contain a use of the declaration to
    indicate the return value of the function.  */
 
+#ifndef INLINER_FOR_JAVA
+static tree
+declare_return_variable (struct inline_data *id, tree return_slot_addr,
+                        tree *use_stmt)
+#else /* INLINER_FOR_JAVA */
 static tree
-declare_return_variable (id, use_stmt)
-     struct inline_data *id;
-     tree *use_stmt;
+declare_return_variable (struct inline_data *id, tree return_slot_addr,
+                        tree *var)
+#endif /* INLINER_FOR_JAVA */
 {
   tree fn = VARRAY_TOP_TREE (id->fns);
   tree result = DECL_RESULT (fn);
+#ifndef INLINER_FOR_JAVA
   tree var;
+#endif /* not INLINER_FOR_JAVA */
   int need_return_decl = 1;
 
   /* We don't need to do anything for functions that don't return
      anything.  */
   if (!result || VOID_TYPE_P (TREE_TYPE (result)))
     {
+#ifndef INLINER_FOR_JAVA
       *use_stmt = NULL_TREE;
+#else /* INLINER_FOR_JAVA */
+      *var = NULL_TREE;
+#endif /* INLINER_FOR_JAVA */
       return NULL_TREE;
     }
 
+#ifndef INLINER_FOR_JAVA
   var = ((*lang_hooks.tree_inlining.copy_res_decl_for_inlining)
         (result, fn, VARRAY_TREE (id->fns, 0), id->decl_map,
-         &need_return_decl, &id->target_exprs));
+         &need_return_decl, return_slot_addr));
 
   /* Register the VAR_DECL as the equivalent for the RESULT_DECL; that
      way, when the RESULT_DECL is encountered, it will be
@@ -636,139 +848,301 @@ declare_return_variable (id, use_stmt)
     *use_stmt = build_stmt (EXPR_STMT,
                            build1 (NOP_EXPR, TREE_TYPE (TREE_TYPE (fn)),
                                    var));
-
   TREE_ADDRESSABLE (*use_stmt) = 1;
 
   /* Build the declaration statement if FN does not return an
      aggregate.  */
   if (need_return_decl)
     return build_stmt (DECL_STMT, var);
+#else /* INLINER_FOR_JAVA */
+  *var = ((*lang_hooks.tree_inlining.copy_res_decl_for_inlining)
+        (result, fn, VARRAY_TREE (id->fns, 0), id->decl_map,
+         &need_return_decl, return_slot_addr));
+
+  splay_tree_insert (id->decl_map,
+                    (splay_tree_key) result,
+                    (splay_tree_value) *var);
+  DECL_IGNORED_P (*var) = 1;
+  if (need_return_decl)
+    return *var;
+#endif /* INLINER_FOR_JAVA */
   /* If FN does return an aggregate, there's no need to declare the
      return variable; we're using a variable in our caller's frame.  */
   else
     return NULL_TREE;
 }
 
-/* Returns non-zero if a function can be inlined as a tree.  */
+/* Returns nonzero if a function can be inlined as a tree.  */
+
+bool
+tree_inlinable_function_p (tree fn)
+{
+  return inlinable_function_p (fn);
+}
+
+/* If *TP is possibly call to alloca, return nonzero.  */
+static tree
+find_alloca_call_1 (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
+                   void *data ATTRIBUTE_UNUSED)
+{
+  if (alloca_call_p (*tp))
+    return *tp;
+  return NULL;
+}
 
-int
-tree_inlinable_function_p (fn)
-     tree fn;
+/* Return subexpression representing possible alloca call, if any.  */
+static tree
+find_alloca_call (tree exp)
 {
-  return inlinable_function_p (fn, NULL);
+  location_t saved_loc = input_location;
+  tree ret = walk_tree_without_duplicates
+               (&exp, find_alloca_call_1, NULL);
+  input_location = saved_loc;
+  return ret;
 }
 
-/* Returns non-zero if FN is a function that can be inlined into the
-   inlining context ID_.  If ID_ is NULL, check whether the function
-   can be inlined at all.  */
+static tree
+find_builtin_longjmp_call_1 (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
+                            void *data ATTRIBUTE_UNUSED)
+{
+  tree exp = *tp, decl;
+
+  if (TREE_CODE (exp) == CALL_EXPR
+      && TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
+      && (decl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
+         TREE_CODE (decl) == FUNCTION_DECL)
+      && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
+      && DECL_FUNCTION_CODE (decl) == BUILT_IN_LONGJMP)
+    return decl;
 
-static int
-inlinable_function_p (fn, id)
-     tree fn;
-     inline_data *id;
+  return NULL;
+}
+
+static tree
+find_builtin_longjmp_call (tree exp)
 {
-  int inlinable;
+  location_t saved_loc = input_location;
+  tree ret = walk_tree_without_duplicates
+               (&exp, find_builtin_longjmp_call_1, NULL);
+  input_location = saved_loc;
+  return ret;
+}
+
+/* Returns nonzero if FN is a function that does not have any
+   fundamental inline blocking properties.  */
+
+static bool
+inlinable_function_p (tree fn)
+{
+  bool inlinable = true;
+  bool calls_builtin_longjmp = false;
+  bool calls_alloca = false;
 
   /* If we've already decided this function shouldn't be inlined,
      there's no need to check again.  */
   if (DECL_UNINLINABLE (fn))
-    return 0;
-
-  /* Assume it is not inlinable.  */
-  inlinable = 0;
-
-  /* If we're not inlining things, then nothing is inlinable.  */
-  if (! flag_inline_trees)
-    ;
-  /* If we're not inlining all functions and the function was not
-     declared `inline', we don't inline it.  Don't think of
-     disregarding DECL_INLINE when flag_inline_trees == 2; it's the
-     front-end that must set DECL_INLINE in this case, because
-     dwarf2out loses if a function is inlined that doesn't have
-     DECL_INLINE set.  */
-  else if (! DECL_INLINE (fn))
-    ;
-  /* We can't inline functions that are too big.  Only allow a single
-     function to eat up half of our budget.  Make special allowance
-     for extern inline functions, though.  */
-  else if (! (*lang_hooks.tree_inlining.disregard_inline_limits) (fn)
-          && DECL_NUM_STMTS (fn) * INSNS_PER_STMT > MAX_INLINE_INSNS / 2)
-    ;
-  /* All is well.  We can inline this function.  Traditionally, GCC
-     has refused to inline functions using alloca, or functions whose
-     values are returned in a PARALLEL, and a few other such obscure
-     conditions.  We are not equally constrained at the tree level.  */
-  else
-    inlinable = 1;
+    return false;
+
+  /* See if there is any language-specific reason it cannot be
+     inlined.  (It is important that this hook be called early because
+     in C++ it may result in template instantiation.)
+     If the function is not inlinable for language-specific reasons,
+     it is left up to the langhook to explain why.  */
+  inlinable = !(*lang_hooks.tree_inlining.cannot_inline_tree_fn) (&fn);
+
+  /* If we don't have the function body available, we can't inline it.
+     However, this should not be recorded since we also get here for
+     forward declared inline functions.  Therefore, return at once.  */
+  if (!DECL_SAVED_TREE (fn))
+    return false;
+
+  /* If we're not inlining at all, then we cannot inline this function.  */
+  else if (!flag_inline_trees)
+    inlinable = false;
+
+  /* Only try to inline functions if DECL_INLINE is set.  This should be
+     true for all functions declared `inline', and for all other functions
+     as well with -finline-functions.
+
+     Don't think of disregarding DECL_INLINE when flag_inline_trees == 2;
+     it's the front-end that must set DECL_INLINE in this case, because
+     dwarf2out loses if a function that does not have DECL_INLINE set is
+     inlined anyway.  That is why we have both DECL_INLINE and
+     DECL_DECLARED_INLINE_P.  */
+  /* FIXME: When flag_inline_trees dies, the check for flag_unit_at_a_time
+           here should be redundant.  */
+  else if (!DECL_INLINE (fn) && !flag_unit_at_a_time)
+    inlinable = false;
+
+#ifdef INLINER_FOR_JAVA
+  /* Synchronized methods can't be inlined.  This is a bug.  */
+  else if (METHOD_SYNCHRONIZED (fn))
+    inlinable = false;
+#endif /* INLINER_FOR_JAVA */
+
+  /* We can't inline functions that call __builtin_longjmp at all.
+     The non-local goto machinery really requires the destination
+     be in a different function.  If we allow the function calling
+     __builtin_longjmp to be inlined into the function calling
+     __builtin_setjmp, Things will Go Awry.  */
+  /* ??? Need front end help to identify "regular" non-local goto.  */
+  else if (find_builtin_longjmp_call (DECL_SAVED_TREE (fn)))
+    calls_builtin_longjmp = true;
+
+  /* Refuse to inline alloca call unless user explicitly forced so as this
+     may change program's memory overhead drastically when the function
+     using alloca is called in loop.  In GCC present in SPEC2000 inlining
+     into schedule_block cause it to require 2GB of ram instead of 256MB.  */
+  else if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn)) == NULL
+          && find_alloca_call (DECL_SAVED_TREE (fn)))
+    calls_alloca = true;
+
+  if (calls_builtin_longjmp || calls_alloca)
+    {
+      /* See if we should warn about uninlinable functions.  Previously,
+        some of these warnings would be issued while trying to expand
+        the function inline, but that would cause multiple warnings
+        about functions that would for example call alloca.  But since
+        this a property of the function, just one warning is enough.
+        As a bonus we can now give more details about the reason why a
+        function is not inlinable.
+        We only warn for functions declared `inline' by the user.  */
+      bool do_warning = (warn_inline
+                        && DECL_INLINE (fn)
+                        && DECL_DECLARED_INLINE_P (fn)
+                        && !DECL_IN_SYSTEM_HEADER (fn));
+
+      if (do_warning && calls_builtin_longjmp)
+       warning ("%Hfunction '%F' can never be inlined because it uses "
+                "setjmp-longjmp exception handling",
+                &DECL_SOURCE_LOCATION (fn), fn);
+      if (do_warning && calls_alloca)
+       warning ("%Hfunction '%F' can never be inlined because it uses "
+                "setjmp-longjmp exception handling",
+                &DECL_SOURCE_LOCATION (fn), fn);
+
+      inlinable = false;
+    }
 
   /* Squirrel away the result so that we don't have to check again.  */
-  DECL_UNINLINABLE (fn) = ! inlinable;
-
-  /* Even if this function is not itself too big to inline, it might
-     be that we've done so much inlining already that we don't want to
-     risk too much inlining any more and thus halve the acceptable
-     size.  */
-  if (! (*lang_hooks.tree_inlining.disregard_inline_limits) (fn)
-      && ((DECL_NUM_STMTS (fn) + (id ? id->inlined_stmts : 0)) * INSNS_PER_STMT
-         > MAX_INLINE_INSNS)
-      && DECL_NUM_STMTS (fn) * INSNS_PER_STMT > MAX_INLINE_INSNS / 4)
-    inlinable = 0;
-
-  if (inlinable && (*lang_hooks.tree_inlining.cannot_inline_tree_fn) (&fn))
-    inlinable = 0;
-  
-  /* If we don't have the function body available, we can't inline
-     it.  */
-  if (! DECL_SAVED_TREE (fn))
-    inlinable = 0;
-
-  /* Check again, language hooks may have modified it.  */
-  if (! inlinable || DECL_UNINLINABLE (fn))
+  DECL_UNINLINABLE (fn) = !inlinable;
+
+  return inlinable;
+}
+
+/* We can't inline functions that are too big.  Only allow a single
+   function to be of MAX_INLINE_INSNS_SINGLE size.  Make special
+   allowance for extern inline functions, though.
+
+   Return nonzero if the function FN can be inlined into the inlining
+   context ID.  */
+
+static int
+limits_allow_inlining (tree fn, inline_data *id)
+{
+  int estimated_insns = 0;
+  size_t i;
+
+  /* Don't even bother if the function is not inlinable.  */
+  if (!inlinable_function_p (fn))
     return 0;
 
-  /* Don't do recursive inlining, either.  We don't record this in
-     DECL_UNINLINABLE; we may be able to inline this function later.  */
-  if (id)
+  /* Investigate the size of the function.  Return at once
+     if the function body size is too large.  */
+  if (!(*lang_hooks.tree_inlining.disregard_inline_limits) (fn))
     {
-      size_t i;
+      int currfn_max_inline_insns;
+
+      /* If we haven't already done so, get an estimate of the number of
+        instructions that will be produces when expanding this function.  */
+      if (!DECL_ESTIMATED_INSNS (fn))
+       DECL_ESTIMATED_INSNS (fn)
+         = (*lang_hooks.tree_inlining.estimate_num_insns) (fn);
+      estimated_insns = DECL_ESTIMATED_INSNS (fn);
+
+      /* We may be here either because fn is declared inline or because
+        we use -finline-functions.  For the second case, we are more
+        restrictive.
+
+        FIXME: -finline-functions should imply -funit-at-a-time, it's
+               about equally expensive but unit-at-a-time produces
+               better code.  */
+      currfn_max_inline_insns = DECL_DECLARED_INLINE_P (fn) ?
+               MAX_INLINE_INSNS_SINGLE : MAX_INLINE_INSNS_AUTO;
+
+      /* If the function is too big to be inlined, adieu.  */
+      if (estimated_insns > currfn_max_inline_insns)
+       return 0;
+
+      /* We now know that we don't disregard the inlining limits and that 
+        we basically should be able to inline this function.
+        We always allow inlining functions if we estimate that they are
+        smaller than MIN_INLINE_INSNS.  Otherwise, investigate further.  */
+      if (estimated_insns > MIN_INLINE_INSNS)
+       {
+         int sum_insns = (id ? id->inlined_insns : 0) + estimated_insns;
 
-      for (i = 0; i < VARRAY_ACTIVE_SIZE (id->fns); ++i)
-       if (VARRAY_TREE (id->fns, i) == fn)
-         return 0;
+         /* In the extreme case that we have exceeded the recursive inlining
+            limit by a huge factor (128), we just say no.
 
-      if (DECL_INLINED_FNS (fn))
-       {
-         int j;
-         tree inlined_fns = DECL_INLINED_FNS (fn);
+            FIXME:  Should not happen in real life, but people have reported
+                    that it actually does!?  */
+         if (sum_insns > MAX_INLINE_INSNS * 128)
+           return 0;
 
-         for (j = 0; j < TREE_VEC_LENGTH (inlined_fns); ++j)
-           if (TREE_VEC_ELT (inlined_fns, j) == VARRAY_TREE (id->fns, 0))
-             return 0;
+         /* If we did not hit the extreme limit, we use a linear function
+            with slope -1/MAX_INLINE_SLOPE to exceedingly decrease the
+            allowable size.  */
+         else if (sum_insns > MAX_INLINE_INSNS)
+           {
+             if (estimated_insns > currfn_max_inline_insns
+                       - (sum_insns - MAX_INLINE_INSNS) / MAX_INLINE_SLOPE)
+               return 0;
+           }
        }
     }
 
-  /* Return the result.  */
-  return inlinable;
+  /* Don't allow recursive inlining.  */
+  for (i = 0; i < VARRAY_ACTIVE_SIZE (id->fns); ++i)
+    if (VARRAY_TREE (id->fns, i) == fn)
+      return 0;
+
+  if (DECL_INLINED_FNS (fn))
+    {
+      int j;
+      tree inlined_fns = DECL_INLINED_FNS (fn);
+
+      for (j = 0; j < TREE_VEC_LENGTH (inlined_fns); ++j)
+       if (TREE_VEC_ELT (inlined_fns, j) == VARRAY_TREE (id->fns, 0))
+         return 0;
+    }
+
+  /* Go ahead, this function can be inlined.  */
+  return 1;
 }
 
 /* If *TP is a CALL_EXPR, replace it with its inline expansion.  */
 
 static tree
-expand_call_inline (tp, walk_subtrees, data)
-     tree *tp;
-     int *walk_subtrees;
-     void *data;
+expand_call_inline (tree *tp, int *walk_subtrees, void *data)
 {
   inline_data *id;
   tree t;
   tree expr;
+  tree stmt;
+#ifndef INLINER_FOR_JAVA
   tree chain;
-  tree fn;
   tree scope_stmt;
   tree use_stmt;
+#else /* INLINER_FOR_JAVA */
+  tree retvar;
+#endif /* INLINER_FOR_JAVA */
+  tree fn;
   tree arg_inits;
   tree *inlined_body;
   splay_tree st;
+  tree args;
+  tree return_slot_addr;
 
   /* See what we've got.  */
   id = (inline_data *) data;
@@ -778,14 +1152,12 @@ expand_call_inline (tp, walk_subtrees, data)
      inside the body of a TARGET_EXPR.  */
   if (TREE_CODE (*tp) == TARGET_EXPR)
     {
+#ifndef INLINER_FOR_JAVA
       int i, len = first_rtl_op (TARGET_EXPR);
 
       /* We're walking our own subtrees.  */
       *walk_subtrees = 0;
 
-      /* Push *TP on the stack of pending TARGET_EXPRs.  */
-      VARRAY_PUSH_TREE (id->target_exprs, *tp);
-
       /* Actually walk over them.  This loop is the body of
         walk_trees, omitting the case where the TARGET_EXPR
         itself is handled.  */
@@ -799,8 +1171,21 @@ expand_call_inline (tp, walk_subtrees, data)
            --id->in_target_cleanup_p;
        }
 
-      /* We're done with this TARGET_EXPR now.  */
-      VARRAY_POP (id->target_exprs);
+      return NULL_TREE;
+#else /* INLINER_FOR_JAVA */
+      abort ();
+#endif /* INLINER_FOR_JAVA */
+    }
+  else if (TREE_CODE (t) == EXPR_WITH_FILE_LOCATION)
+    {
+      /* We're walking the subtree directly.  */
+      *walk_subtrees = 0;
+      /* Update the source position.  */
+      push_srcloc (EXPR_WFL_FILENAME (t), EXPR_WFL_LINENO (t));
+      walk_tree (&EXPR_WFL_NODE (t), expand_call_inline, data,
+                id->tree_pruner);
+      /* Restore the original source position.  */
+      pop_srcloc ();
 
       return NULL_TREE;
     }
@@ -821,6 +1206,10 @@ expand_call_inline (tp, walk_subtrees, data)
   if (!fn)
     return NULL_TREE;
 
+  /* Turn forward declarations into real ones.  */
+  if (flag_unit_at_a_time)
+    fn = cgraph_node (fn)->decl;
+
   /* If fn is a declaration of a function in a nested scope that was
      globally declared inline, we don't set its DECL_INITIAL.
      However, we can't blindly follow DECL_ABSTRACT_ORIGIN because the
@@ -835,8 +1224,19 @@ expand_call_inline (tp, walk_subtrees, data)
 
   /* Don't try to inline functions that are not well-suited to
      inlining.  */
-  if (!inlinable_function_p (fn, id))
-    return NULL_TREE;
+  if ((flag_unit_at_a_time
+       && (!DECL_SAVED_TREE (fn) || !cgraph_inline_p (id->current_decl, fn)))
+      || (!flag_unit_at_a_time && !limits_allow_inlining (fn, id)))
+    {
+      if (warn_inline && DECL_INLINE (fn) && DECL_DECLARED_INLINE_P (fn)
+         && !DECL_IN_SYSTEM_HEADER (fn))
+       {
+         warning ("%Hinlining failed in call to '%F'",
+                   &DECL_SOURCE_LOCATION (fn), fn);
+         warning ("called from here");
+       }
+      return NULL_TREE;
+    }
 
   if (! (*lang_hooks.tree_inlining.start_inlining) (fn))
     return NULL_TREE;
@@ -846,14 +1246,26 @@ expand_call_inline (tp, walk_subtrees, data)
      line numbers corresponding to the function we are calling.  We
      wrap the whole inlined body in an EXPR_WITH_FILE_AND_LINE as well
      because individual statements don't record the filename.  */
-  push_srcloc (fn->decl.filename, fn->decl.linenum);
+  push_srcloc (DECL_SOURCE_FILE (fn), DECL_SOURCE_LINE (fn));
 
+#ifndef INLINER_FOR_JAVA
   /* Build a statement-expression containing code to initialize the
      arguments, the actual inline expansion of the body, and a label
      for the return statements within the function to jump to.  The
      type of the statement expression is the return type of the
      function call.  */
-  expr = build1 (STMT_EXPR, TREE_TYPE (TREE_TYPE (fn)), NULL_TREE);
+  expr = build1 (STMT_EXPR, TREE_TYPE (TREE_TYPE (fn)), make_node (COMPOUND_STMT));
+  /* There is no scope associated with the statement-expression.  */
+  STMT_EXPR_NO_SCOPE (expr) = 1;
+  stmt = STMT_EXPR_STMT (expr);
+#else /* INLINER_FOR_JAVA */
+  /* Build a block containing code to initialize the arguments, the
+     actual inline expansion of the body, and a label for the return
+     statements within the function to jump to.  The type of the
+     statement expression is the return type of the function call.  */
+  stmt = NULL;
+  expr = build (BLOCK, TREE_TYPE (TREE_TYPE (fn)), stmt);
+#endif /* INLINER_FOR_JAVA */
 
   /* Local declarations will be replaced by their equivalents in this
      map.  */
@@ -862,14 +1274,39 @@ expand_call_inline (tp, walk_subtrees, data)
                                 NULL, NULL);
 
   /* Initialize the parameters.  */
-  arg_inits = initialize_inlined_parameters (id, TREE_OPERAND (t, 1), fn);
+  args = TREE_OPERAND (t, 1);
+  return_slot_addr = NULL_TREE;
+  if (CALL_EXPR_HAS_RETURN_SLOT_ADDR (t))
+    {
+      return_slot_addr = TREE_VALUE (args);
+      args = TREE_CHAIN (args);
+    }
+
+#ifndef INLINER_FOR_JAVA
+  arg_inits = initialize_inlined_parameters (id, args, fn);
   /* Expand any inlined calls in the initializers.  Do this before we
      push FN on the stack of functions we are inlining; we want to
      inline calls to FN that appear in the initializers for the
      parameters.  */
   expand_calls_inline (&arg_inits, id);
   /* And add them to the tree.  */
-  STMT_EXPR_STMT (expr) = chainon (STMT_EXPR_STMT (expr), arg_inits);
+  COMPOUND_BODY (stmt) = chainon (COMPOUND_BODY (stmt), arg_inits);
+#else /* INLINER_FOR_JAVA */
+  arg_inits = initialize_inlined_parameters (id, args, fn, expr);
+  if (arg_inits)
+    {
+      /* Expand any inlined calls in the initializers.  Do this before we
+        push FN on the stack of functions we are inlining; we want to
+        inline calls to FN that appear in the initializers for the
+        parameters.  */
+      expand_calls_inline (&arg_inits, id);
+
+      /* And add them to the tree.  */
+      BLOCK_EXPR_BODY (expr) = add_stmt_to_compound (BLOCK_EXPR_BODY (expr),
+                                                    TREE_TYPE (arg_inits),
+                                                    arg_inits);
+    }
+#endif /* INLINER_FOR_JAVA */
 
   /* Record the function we are about to inline so that we can avoid
      recursing into it.  */
@@ -897,6 +1334,7 @@ expand_call_inline (tp, walk_subtrees, data)
       || TREE_CODE (DECL_INITIAL (fn)) != BLOCK)
     abort ();
 
+#ifndef INLINER_FOR_JAVA
   /* Create a block to put the parameters in.  We have to do this
      after the parameters have been remapped because remapping
      parameters is different from remapping ordinary variables.  */
@@ -904,8 +1342,8 @@ expand_call_inline (tp, walk_subtrees, data)
   SCOPE_BEGIN_P (scope_stmt) = 1;
   SCOPE_NO_CLEANUPS_P (scope_stmt) = 1;
   remap_block (scope_stmt, DECL_ARGUMENTS (fn), id);
-  TREE_CHAIN (scope_stmt) = STMT_EXPR_STMT (expr);
-  STMT_EXPR_STMT (expr) = scope_stmt;
+  TREE_CHAIN (scope_stmt) = COMPOUND_BODY (stmt);
+  COMPOUND_BODY (stmt) = scope_stmt;
 
   /* Tell the debugging backends that this block represents the
      outermost scope of the inlined function.  */
@@ -913,34 +1351,84 @@ expand_call_inline (tp, walk_subtrees, data)
     BLOCK_ABSTRACT_ORIGIN (SCOPE_STMT_BLOCK (scope_stmt)) = DECL_ORIGIN (fn);
 
   /* Declare the return variable for the function.  */
-  STMT_EXPR_STMT (expr)
-    = chainon (STMT_EXPR_STMT (expr),
-              declare_return_variable (id, &use_stmt));
+  COMPOUND_BODY (stmt)
+    = chainon (COMPOUND_BODY (stmt),
+              declare_return_variable (id, return_slot_addr, &use_stmt));
+#else /* INLINER_FOR_JAVA */
+  {
+    /* Declare the return variable for the function.  */
+    tree decl = declare_return_variable (id, return_slot_addr, &retvar);
+    if (retvar)
+      {
+       tree *next = &BLOCK_VARS (expr);
+       while (*next)
+         next = &TREE_CHAIN (*next);
+       *next = decl;
+      }
+  }
+#endif /* INLINER_FOR_JAVA */
 
   /* After we've initialized the parameters, we insert the body of the
      function itself.  */
-  inlined_body = &STMT_EXPR_STMT (expr);
+#ifndef INLINER_FOR_JAVA
+  inlined_body = &COMPOUND_BODY (stmt);
   while (*inlined_body)
     inlined_body = &TREE_CHAIN (*inlined_body);
   *inlined_body = copy_body (id);
-
-  /* Close the block for the parameters.  */
-  scope_stmt = build_stmt (SCOPE_STMT, DECL_INITIAL (fn));
-  SCOPE_NO_CLEANUPS_P (scope_stmt) = 1;
-  remap_block (scope_stmt, NULL_TREE, id);
-  STMT_EXPR_STMT (expr)
-    = chainon (STMT_EXPR_STMT (expr), scope_stmt);
+#else /* INLINER_FOR_JAVA */
+  {
+    tree new_body;
+    java_inlining_map_static_initializers (fn, id->decl_map);
+    new_body = copy_body (id);
+    TREE_TYPE (new_body) = TREE_TYPE (TREE_TYPE (fn));
+    BLOCK_EXPR_BODY (expr)
+      = add_stmt_to_compound (BLOCK_EXPR_BODY (expr),
+                             TREE_TYPE (new_body), new_body);
+    inlined_body = &BLOCK_EXPR_BODY (expr);
+  }
+#endif /* INLINER_FOR_JAVA */
 
   /* After the body of the function comes the RET_LABEL.  This must come
-     before we evaluate the returned value below, because that evalulation
+     before we evaluate the returned value below, because that evaluation
      may cause RTL to be generated.  */
-  STMT_EXPR_STMT (expr)
-    = chainon (STMT_EXPR_STMT (expr),
+#ifndef INLINER_FOR_JAVA
+  COMPOUND_BODY (stmt)
+    = chainon (COMPOUND_BODY (stmt),
               build_stmt (LABEL_STMT, id->ret_label));
+#else /* INLINER_FOR_JAVA */
+  {
+    tree label = build1 (LABEL_EXPR, void_type_node, id->ret_label);
+    BLOCK_EXPR_BODY (expr)
+      = add_stmt_to_compound (BLOCK_EXPR_BODY (expr), void_type_node, label);
+    TREE_SIDE_EFFECTS (label) = TREE_SIDE_EFFECTS (t);
+  }
+#endif /* INLINER_FOR_JAVA */
 
   /* Finally, mention the returned value so that the value of the
      statement-expression is the returned value of the function.  */
-  STMT_EXPR_STMT (expr) = chainon (STMT_EXPR_STMT (expr), use_stmt);
+#ifndef INLINER_FOR_JAVA
+  COMPOUND_BODY (stmt) = chainon (COMPOUND_BODY (stmt), use_stmt);
+
+  /* Close the block for the parameters.  */
+  scope_stmt = build_stmt (SCOPE_STMT, DECL_INITIAL (fn));
+  SCOPE_NO_CLEANUPS_P (scope_stmt) = 1;
+  remap_block (scope_stmt, NULL_TREE, id);
+  COMPOUND_BODY (stmt)
+    = chainon (COMPOUND_BODY (stmt), scope_stmt);
+#else /* INLINER_FOR_JAVA */
+  if (retvar)
+    {
+      /* Mention the retvar.  If the return type of the function was
+        promoted, convert it back to the expected type.  */
+      if (TREE_TYPE (TREE_TYPE (fn)) != TREE_TYPE (retvar))
+       retvar = build1 (NOP_EXPR, TREE_TYPE (TREE_TYPE (fn)), retvar);
+      BLOCK_EXPR_BODY (expr)
+       = add_stmt_to_compound (BLOCK_EXPR_BODY (expr),
+                               TREE_TYPE (retvar), retvar);
+    }
+
+  java_inlining_merge_static_initializers (fn, id->decl_map);
+#endif /* INLINER_FOR_JAVA */
 
   /* Clean up.  */
   splay_tree_delete (id->decl_map);
@@ -952,11 +1440,15 @@ expand_call_inline (tp, walk_subtrees, data)
   /* Replace the call by the inlined body.  Wrap it in an
      EXPR_WITH_FILE_LOCATION so that we'll get debugging line notes
      pointing to the right place.  */
+#ifndef INLINER_FOR_JAVA
   chain = TREE_CHAIN (*tp);
+#endif /* INLINER_FOR_JAVA */
   *tp = build_expr_wfl (expr, DECL_SOURCE_FILE (fn), DECL_SOURCE_LINE (fn),
                        /*col=*/0);
   EXPR_WFL_EMIT_LINE_NOTE (*tp) = 1;
+#ifndef INLINER_FOR_JAVA
   TREE_CHAIN (*tp) = chain;
+#endif /* not INLINER_FOR_JAVA */
   pop_srcloc ();
 
   /* If the value of the new expression is ignored, that's OK.  We
@@ -965,17 +1457,30 @@ expand_call_inline (tp, walk_subtrees, data)
   TREE_USED (*tp) = 1;
 
   /* Our function now has more statements than it did before.  */
-  DECL_NUM_STMTS (VARRAY_TREE (id->fns, 0)) += DECL_NUM_STMTS (fn);
-  id->inlined_stmts += DECL_NUM_STMTS (fn);
+  DECL_ESTIMATED_INSNS (VARRAY_TREE (id->fns, 0)) += DECL_ESTIMATED_INSNS (fn);
+  /* For accounting, subtract one for the saved call/ret.  */
+  id->inlined_insns += DECL_ESTIMATED_INSNS (fn) - 1;
+
+  /* Update callgraph if needed.  */
+  if (id->decl && flag_unit_at_a_time)
+    {
+      cgraph_remove_call (id->decl, fn);
+      cgraph_create_edges (id->decl, *inlined_body);
+    }
 
   /* Recurse into the body of the just inlined function.  */
-  expand_calls_inline (inlined_body, id);
+  {
+    tree old_decl = id->current_decl;
+    id->current_decl = fn;
+    expand_calls_inline (inlined_body, id);
+    id->current_decl = old_decl;
+  }
   VARRAY_POP (id->fns);
 
   /* If we've returned to the top level, clear out the record of how
      much inlining has been done.  */
   if (VARRAY_ACTIVE_SIZE (id->fns) == id->first_inlined_fn)
-    id->inlined_stmts = 0;
+    id->inlined_insns = 0;
 
   /* Don't walk into subtrees.  We've already handled them above.  */
   *walk_subtrees = 0;
@@ -985,14 +1490,11 @@ expand_call_inline (tp, walk_subtrees, data)
   /* Keep iterating.  */
   return NULL_TREE;
 }
-
 /* Walk over the entire tree *TP, replacing CALL_EXPRs with inline
    expansions as appropriate.  */
 
 static void
-expand_calls_inline (tp, id)
-     tree *tp;
-     inline_data *id;
+expand_calls_inline (tree *tp, inline_data *id)
 {
   /* Search through *TP, replacing all calls to inline functions by
      appropriate equivalents.  Use walk_tree in no-duplicates mode
@@ -1006,18 +1508,22 @@ expand_calls_inline (tp, id)
 /* Expand calls to inline functions in the body of FN.  */
 
 void
-optimize_inline_calls (fn)
-     tree fn;
+optimize_inline_calls (tree fn)
 {
   inline_data id;
   tree prev_fn;
-  
+
   /* Clear out ID.  */
   memset (&id, 0, sizeof (id));
 
+  id.decl = fn;
+  id.current_decl = fn;
   /* Don't allow recursion into FN.  */
   VARRAY_TREE_INIT (id.fns, 32, "fns");
   VARRAY_PUSH_TREE (id.fns, fn);
+  if (!DECL_ESTIMATED_INSNS (fn))
+    DECL_ESTIMATED_INSNS (fn) 
+      = (*lang_hooks.tree_inlining.estimate_num_insns) (fn);
   /* Or any functions that aren't finished yet.  */
   prev_fn = NULL_TREE;
   if (current_function_decl)
@@ -1028,9 +1534,6 @@ optimize_inline_calls (fn)
 
   prev_fn = ((*lang_hooks.tree_inlining.add_pending_fn_decls)
             (&id.fns, prev_fn));
-  
-  /* Create the stack of TARGET_EXPRs.  */
-  VARRAY_TREE_INIT (id.target_exprs, 32, "target_exprs");
 
   /* Create the list of functions this call will inline.  */
   VARRAY_TREE_INIT (id.inlined_fns, 32, "inlined_fns");
@@ -1047,17 +1550,15 @@ optimize_inline_calls (fn)
 
   /* Clean up.  */
   htab_delete (id.tree_pruner);
-  VARRAY_FREE (id.fns);
-  VARRAY_FREE (id.target_exprs);
   if (DECL_LANG_SPECIFIC (fn))
     {
       tree ifn = make_tree_vec (VARRAY_ACTIVE_SIZE (id.inlined_fns));
-      
-      memcpy (&TREE_VEC_ELT (ifn, 0), &VARRAY_TREE (id.inlined_fns, 0),
-             VARRAY_ACTIVE_SIZE (id.inlined_fns) * sizeof (tree));
+
+      if (VARRAY_ACTIVE_SIZE (id.inlined_fns))
+       memcpy (&TREE_VEC_ELT (ifn, 0), &VARRAY_TREE (id.inlined_fns, 0),
+               VARRAY_ACTIVE_SIZE (id.inlined_fns) * sizeof (tree));
       DECL_INLINED_FNS (fn) = ifn;
     }
-  VARRAY_FREE (id.inlined_fns);
 }
 
 /* FN is a function that has a complete body, and CLONE is a function
@@ -1065,9 +1566,7 @@ optimize_inline_calls (fn)
    declarations according to the ARG_MAP splay_tree.  */
 
 void
-clone_body (clone, fn, arg_map)
-     tree clone, fn;
-     void *arg_map;
+clone_body (tree clone, tree fn, void *arg_map)
 {
   inline_data id;
 
@@ -1087,9 +1586,6 @@ clone_body (clone, fn, arg_map)
 
   /* Actually copy the body.  */
   TREE_CHAIN (DECL_SAVED_TREE (clone)) = copy_body (&id);
-
-  /* Clean up.  */
-  VARRAY_FREE (id.fns);
 }
 
 /* Apply FUNC to all the sub-trees of TP in a pre-order traversal.
@@ -1099,18 +1595,14 @@ clone_body (clone, fn, arg_map)
    to record the nodes visited, and to avoid visiting a node more than
    once.  */
 
-tree 
-walk_tree (tp, func, data, htab_)
-     tree *tp;
-     walk_tree_fn func;
-     void *data;
-     void *htab_;
+tree
+walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_)
 {
   htab_t htab = (htab_t) htab_;
   enum tree_code code;
   int walk_subtrees;
   tree result;
-  
+
 #define WALK_SUBTREE(NODE)                             \
   do                                                   \
     {                                                  \
@@ -1136,13 +1628,12 @@ walk_tree (tp, func, data, htab_)
   if (htab)
     {
       void **slot;
-      
+
       /* Don't walk the same tree twice, if the user has requested
          that we avoid doing so.  */
-      if (htab_find (htab, *tp))
-       return NULL_TREE;
-      /* If we haven't already seen this node, add it to the table.  */
       slot = htab_find_slot (htab, *tp, INSERT);
+      if (*slot)
+       return NULL_TREE;
       *slot = *tp;
     }
 
@@ -1156,11 +1647,12 @@ walk_tree (tp, func, data, htab_)
 
   code = TREE_CODE (*tp);
 
+#ifndef INLINER_FOR_JAVA
   /* Even if we didn't, FUNC may have decided that there was nothing
      interesting below this point in the tree.  */
   if (!walk_subtrees)
     {
-      if (statement_code_p (code) || code == TREE_LIST
+      if (STATEMENT_CODE_P (code) || code == TREE_LIST
          || (*lang_hooks.tree_inlining.tree_chain_matters_p) (*tp))
        /* But we still need to check our siblings.  */
        WALK_SUBTREE_TAIL (TREE_CHAIN (*tp));
@@ -1169,16 +1661,21 @@ walk_tree (tp, func, data, htab_)
     }
 
   /* Handle common cases up front.  */
-  if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
-      || TREE_CODE_CLASS (code) == 'r'
-      || TREE_CODE_CLASS (code) == 's')
+  if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)))
+#else /* INLINER_FOR_JAVA */
+  if (code != EXIT_BLOCK_EXPR
+      && code != SAVE_EXPR
+      && IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)))
+#endif /* INLINER_FOR_JAVA */
     {
       int i, len;
 
+#ifndef INLINER_FOR_JAVA
       /* Set lineno here so we get the right instantiation context
         if we call instantiate_decl from inlinable_function_p.  */
-      if (statement_code_p (code) && !STMT_LINENO_FOR_FN_P (*tp))
-       lineno = STMT_LINENO (*tp);
+      if (STATEMENT_CODE_P (code) && !STMT_LINENO_FOR_FN_P (*tp))
+       input_line = STMT_LINENO (*tp);
+#endif /* not INLINER_FOR_JAVA */
 
       /* Walk over all the sub-trees of this operand.  */
       len = first_rtl_op (code);
@@ -1192,12 +1689,13 @@ walk_tree (tp, func, data, htab_)
       for (i = 0; i < len; ++i)
        WALK_SUBTREE (TREE_OPERAND (*tp, i));
 
+#ifndef INLINER_FOR_JAVA
       /* For statements, we also walk the chain so that we cover the
         entire statement tree.  */
-      if (statement_code_p (code))
+      if (STATEMENT_CODE_P (code))
        {
-         if (code == DECL_STMT 
-             && DECL_STMT_DECL (*tp) 
+         if (code == DECL_STMT
+             && DECL_STMT_DECL (*tp)
              && DECL_P (DECL_STMT_DECL (*tp)))
            {
              /* Walk the DECL_INITIAL and DECL_SIZE.  We don't want to walk
@@ -1214,6 +1712,7 @@ walk_tree (tp, func, data, htab_)
          WALK_SUBTREE_TAIL (TREE_CHAIN (*tp));
        }
 
+#endif /* not INLINER_FOR_JAVA */
       /* We didn't find what we were looking for.  */
       return NULL_TREE;
     }
@@ -1221,6 +1720,12 @@ walk_tree (tp, func, data, htab_)
     {
       WALK_SUBTREE_TAIL (TREE_TYPE (*tp));
     }
+  else if (TREE_CODE_CLASS (code) == 't')
+    {
+      WALK_SUBTREE (TYPE_SIZE (*tp));
+      WALK_SUBTREE (TYPE_SIZE_UNIT (*tp));
+      /* Also examine various special fields, below.  */
+    }
 
   result = (*lang_hooks.tree_inlining.walk_subtrees) (tp, &walk_subtrees, func,
                                                      data, htab);
@@ -1246,6 +1751,7 @@ walk_tree (tp, func, data, htab_)
     case ENUMERAL_TYPE:
     case BLOCK:
     case RECORD_TYPE:
+    case CHAR_TYPE:
       /* None of thse have subtrees other than those already walked
          above.  */
       break;
@@ -1309,6 +1815,14 @@ walk_tree (tp, func, data, htab_)
       WALK_SUBTREE (TREE_TYPE (*tp));
       WALK_SUBTREE_TAIL (TYPE_OFFSET_BASETYPE (*tp));
 
+#ifdef INLINER_FOR_JAVA
+    case EXIT_BLOCK_EXPR:
+      WALK_SUBTREE_TAIL (TREE_OPERAND (*tp, 1));
+
+    case SAVE_EXPR:
+      WALK_SUBTREE_TAIL (TREE_OPERAND (*tp, 0));
+#endif /* INLINER_FOR_JAVA */
+
     default:
       abort ();
     }
@@ -1317,16 +1831,14 @@ walk_tree (tp, func, data, htab_)
   return NULL_TREE;
 
 #undef WALK_SUBTREE
+#undef WALK_SUBTREE_TAIL
 }
 
-/* Like walk_tree, but does not walk duplicate nodes more than 
+/* Like walk_tree, but does not walk duplicate nodes more than
    once.  */
 
-tree 
-walk_tree_without_duplicates (tp, func, data)
-     tree *tp;
-     walk_tree_fn func;
-     void *data;
+tree
+walk_tree_without_duplicates (tree *tp, walk_tree_fn func, void *data)
 {
   tree result;
   htab_t htab;
@@ -1340,18 +1852,13 @@ walk_tree_without_duplicates (tp, func, data)
 /* Passed to walk_tree.  Copies the node pointed to, if appropriate.  */
 
 tree
-copy_tree_r (tp, walk_subtrees, data)
-     tree *tp;
-     int *walk_subtrees;
-     void *data ATTRIBUTE_UNUSED;
+copy_tree_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
 {
   enum tree_code code = TREE_CODE (*tp);
 
   /* We make copies of most nodes.  */
   if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
-      || TREE_CODE_CLASS (code) == 'r'
       || TREE_CODE_CLASS (code) == 'c'
-      || TREE_CODE_CLASS (code) == 's'
       || code == TREE_LIST
       || code == TREE_VEC
       || (*lang_hooks.tree_inlining.tree_chain_matters_p) (*tp))
@@ -1366,17 +1873,22 @@ copy_tree_r (tp, walk_subtrees, data)
       /* Now, restore the chain, if appropriate.  That will cause
         walk_tree to walk into the chain as well.  */
       if (code == PARM_DECL || code == TREE_LIST
+#ifndef INLINER_FOR_JAVA
          || (*lang_hooks.tree_inlining.tree_chain_matters_p) (*tp)
-         || statement_code_p (code))
+         || STATEMENT_CODE_P (code))
        TREE_CHAIN (*tp) = chain;
 
       /* For now, we don't update BLOCKs when we make copies.  So, we
         have to nullify all scope-statements.  */
       if (TREE_CODE (*tp) == SCOPE_STMT)
        SCOPE_STMT_BLOCK (*tp) = NULL_TREE;
+#else /* INLINER_FOR_JAVA */
+         || (*lang_hooks.tree_inlining.tree_chain_matters_p) (*tp))
+       TREE_CHAIN (*tp) = chain;
+#endif /* INLINER_FOR_JAVA */
     }
-  else if (TREE_CODE_CLASS (code) == 't')
-    /* There's no need to copy types, or anything beneath them.  */
+  else if (TREE_CODE_CLASS (code) == 't' && !variably_modified_type_p (*tp))
+    /* Types only need to be copied if they are variably modified.  */
     *walk_subtrees = 0;
 
   return NULL_TREE;
@@ -1388,18 +1900,14 @@ copy_tree_r (tp, walk_subtrees, data)
    ST.  FN is the function into which the copy will be placed.  */
 
 void
-remap_save_expr (tp, st_, fn, walk_subtrees)
-     tree *tp;
-     void *st_;
-     tree fn;
-     int *walk_subtrees;
+remap_save_expr (tree *tp, void *st_, tree fn, int *walk_subtrees)
 {
   splay_tree st = (splay_tree) st_;
   splay_tree_node n;
 
   /* See if we already encountered this SAVE_EXPR.  */
   n = splay_tree_lookup (st, (splay_tree_key) *tp);
-      
+
   /* If we didn't already remap this SAVE_EXPR, do so now.  */
   if (!n)
     {
@@ -1426,3 +1934,20 @@ remap_save_expr (tp, st_, fn, walk_subtrees)
   /* Replace this SAVE_EXPR with the copy.  */
   *tp = (tree) n->value;
 }
+
+#ifdef INLINER_FOR_JAVA
+/* Add STMT to EXISTING if possible, otherwise create a new
+   COMPOUND_EXPR and add STMT to it.  */
+
+static tree
+add_stmt_to_compound (tree existing, tree type, tree stmt)
+{
+  if (!stmt)
+    return existing;
+  else if (existing)
+    return build (COMPOUND_EXPR, type, existing, stmt);
+  else
+    return stmt;
+}
+
+#endif /* INLINER_FOR_JAVA */