This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Patch: Don't free local variables if a jsr has been emitted


In the Java VM, a jsr calls a subroutine that is within the dynamic
scope of the block from which it is called.  Local variables at the
site of the call are potentially live in the subroutine.

At present, we generate incorrect code because we recycle stack slots
when we leave the scope in which the associated variables were
declared.

This patch is simple and brutal: if a jsr has been emitted in a block,
we don't recycle any of that block's stack slots.  That is, they
remain allocated until the end of the method.

This has the disadvantage of wasting some local variable space.
However, it is far better than what we do at the moment, which is
silently generate incorrect code.

A real fix for this problem will properly track variable lifetimes.

Andrew.

2003-03-12  Andrew Haley  <aph at redhat dot com>

	* jcf-write.c (struct jcf_partial): num_jsrs: new field.
	(maybe_free_localvar): Renamed from localvar_free.
	Add new arg, really.
	(generate_bytecode_insns): Set new variable, jsrs.
	Only free local vars if no jsr insns have been emittted.
	Call maybe_free_localvar, not localvar_free.

Index: jcf-write.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/jcf-write.c,v
retrieving revision 1.120
diff -u -r1.120 jcf-write.c
--- jcf-write.c	29 Jan 2003 01:19:40 -0000	1.120
+++ jcf-write.c	11 Feb 2003 13:44:16 -0000
@@ -279,6 +279,9 @@
 
   /* Information about the current switch statement. */
   struct jcf_switch_state *sw_state;
+
+  /* The count of jsr instructions that have been emmitted.  */
+  long num_jsrs;
 };
 
 static void generate_bytecode_insns (tree, int, struct jcf_partial *);
@@ -293,7 +296,7 @@
 static struct jcf_block * get_jcf_label_here (struct jcf_partial *);
 static void put_linenumber (int, struct jcf_partial *);
 static void localvar_alloc (tree, struct jcf_partial *);
-static void localvar_free (tree, struct jcf_partial *);
+static void maybe_free_localvar (tree, struct jcf_partial *, int);
 static int get_access_flags (tree);
 static void write_chunks (FILE *, struct chunk *);
 static int adjust_typed_op (tree, int);
@@ -600,7 +603,7 @@
 }
 
 static void
-localvar_free (tree decl, struct jcf_partial *state)
+maybe_free_localvar (tree decl, struct jcf_partial *state, int really)
 {
   struct jcf_block *end_label = get_jcf_label_here (state);
   int index = DECL_LOCAL_INDEX (decl);
@@ -612,6 +615,8 @@
 
   if (info->decl != decl)
     abort ();
+  if (! really)
+    return;
   ptr[0] = NULL;
   if (wide)
     {
@@ -1065,6 +1070,7 @@
   OP1 (OPCODE_jsr);
   /* Value is 1 byte from reloc back to start of instruction.  */
   emit_reloc (RELOCATION_VALUE_1, OPCODE_jsr_w, target, state);
+  state->num_jsrs++;
 }
 
 /* Generate code to evaluate EXP.  If the result is true,
@@ -1346,7 +1352,7 @@
 	  emit_store (state->return_value_decl, state);
 	  call_cleanups (NULL, state);
 	  emit_load (state->return_value_decl, state);
-	  /* If we call localvar_free (state->return_value_decl, state),
+	  /* If we call maybe_free_localvar (state->return_value_decl, state, 1),
 	     then we risk the save decl erroneously re-used in the
 	     finalizer.  Instead, we keep the state->return_value_decl
 	     allocated through the rest of the method.  This is not
@@ -1383,6 +1389,7 @@
 	{
 	  tree local;
 	  tree body = BLOCK_EXPR_BODY (exp);
+	  long jsrs = state->num_jsrs;
 	  for (local = BLOCK_EXPR_DECLS (exp); local; )
 	    {
 	      tree next = TREE_CHAIN (local);
@@ -1396,10 +1403,11 @@
 	      body = TREE_OPERAND (body, 1);
 	    }
 	  generate_bytecode_insns (body, target, state);
+	  
 	  for (local = BLOCK_EXPR_DECLS (exp); local; )
 	    {
 	      tree next = TREE_CHAIN (local);
-	      localvar_free (local, state);
+	      maybe_free_localvar (local, state, state->num_jsrs <= jsrs);
 	      local = next;
 	    }
 	}
@@ -2353,8 +2361,8 @@
 	if (CAN_COMPLETE_NORMALLY (finally))
 	  {
 	    maybe_wide (OPCODE_ret, DECL_LOCAL_INDEX (return_link), state);
-	    localvar_free (exception_decl, state);
-	    localvar_free (return_link, state);
+	    maybe_free_localvar (exception_decl, state, 1);
+	    maybe_free_localvar (return_link, state, 1);
 	    define_jcf_label (finished_label, state);
 	  }
       }
@@ -2951,6 +2965,7 @@
 	  get_jcf_label_here (state);  /* Force a first block. */
 	  for (t = DECL_ARGUMENTS (part);  t != NULL_TREE;  t = TREE_CHAIN (t))
 	    localvar_alloc (t, state);
+	  state->num_jsrs = 0;
 	  generate_bytecode_insns (body, IGNORE_TARGET, state);
 	  if (CAN_COMPLETE_NORMALLY (body))
 	    {
@@ -2960,9 +2975,9 @@
 	      OP1 (OPCODE_return);
 	    }
 	  for (t = DECL_ARGUMENTS (part);  t != NULL_TREE;  t = TREE_CHAIN (t))
-	    localvar_free (t, state);
+	    maybe_free_localvar (t, state, 1);
 	  if (state->return_value_decl != NULL_TREE)
-	    localvar_free (state->return_value_decl, state);
+	    maybe_free_localvar (state->return_value_decl, state, 1);
 	  finish_jcf_block (state);
 	  perform_relocations (state);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]