]> gcc.gnu.org Git - gcc.git/blobdiff - gcc/java/jcf-write.c
buffer.h: PROTO -> PARAMS.
[gcc.git] / gcc / java / jcf-write.c
index 1b5539b4b924364dbca1c3780a94005769d9c966..0577dcd01f1dc4e88fdd57104ee94a42b17c758d 100644 (file)
@@ -1,5 +1,5 @@
 /* Write out a Java(TM) class file.
-   Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -23,21 +23,18 @@ The Free Software Foundation is independent of Sun Microsystems, Inc.  */
 
 #include "config.h"
 #include "system.h"
+#include "jcf.h"
 #include "tree.h"
 #include "java-tree.h"
-#include "jcf.h"
 #include "obstack.h"
 #undef AND
 #include "rtl.h"
+#include "flags.h"
 #include "java-opcodes.h"
 #include "parse.h" /* for BLOCK_EXPR_BODY */
 #include "buffer.h"
 #include "toplev.h"
 
-#ifndef DIR_SEPARATOR
-#define DIR_SEPARATOR '/'
-#endif
-
 extern struct obstack temporary_obstack;
 
 /* Base directory in which `.class' files should be written.
@@ -185,6 +182,9 @@ struct jcf_relocation
   struct jcf_block *label;
 };
 
+#define RELOCATION_VALUE_0 ((HOST_WIDE_INT)0)
+#define RELOCATION_VALUE_1 ((HOST_WIDE_INT)1)
+
 /* State for single catch clause. */
 
 struct jcf_handler
@@ -271,7 +271,70 @@ struct jcf_partial
   struct jcf_switch_state *sw_state;
 };
 
-static void generate_bytecode_insns PROTO ((tree, int, struct jcf_partial *));
+static void generate_bytecode_insns PARAMS ((tree, int, struct jcf_partial *));
+static struct chunk * alloc_chunk PARAMS ((struct chunk *, unsigned char *,
+                                         int, struct obstack *));
+static unsigned char * append_chunk PARAMS ((unsigned char *, int,
+                                           struct jcf_partial *));
+static void append_chunk_copy PARAMS ((unsigned char *, int,
+                                     struct jcf_partial *));
+static struct jcf_block * gen_jcf_label PARAMS ((struct jcf_partial *));
+static void finish_jcf_block PARAMS ((struct jcf_partial *));
+static void define_jcf_label PARAMS ((struct jcf_block *,
+                                    struct jcf_partial *));
+static struct jcf_block * get_jcf_label_here PARAMS ((struct jcf_partial *));
+static void put_linenumber PARAMS ((int, struct jcf_partial *));
+static void localvar_alloc PARAMS ((tree, struct jcf_partial *));
+static void localvar_free PARAMS ((tree, struct jcf_partial *));
+static int get_access_flags PARAMS ((tree));
+static void write_chunks PARAMS ((FILE *, struct chunk *));
+static int adjust_typed_op PARAMS ((tree, int));
+static void generate_bytecode_conditional PARAMS ((tree, struct jcf_block *,
+                                                 struct jcf_block *, int,
+                                                 struct jcf_partial *));
+static void generate_bytecode_return PARAMS ((tree, struct jcf_partial *));
+static void perform_relocations PARAMS ((struct jcf_partial *));
+static void init_jcf_state PARAMS ((struct jcf_partial *, struct obstack *));
+static void init_jcf_method PARAMS ((struct jcf_partial *, tree));
+static void release_jcf_state PARAMS ((struct jcf_partial *));
+static struct chunk * generate_classfile PARAMS ((tree, struct jcf_partial *));
+static struct jcf_handler *alloc_handler PARAMS ((struct jcf_block *,
+                                                struct jcf_block *,
+                                                struct jcf_partial *));
+static void emit_iinc PARAMS ((tree, HOST_WIDE_INT, struct jcf_partial *));
+static void emit_reloc PARAMS ((HOST_WIDE_INT, int, struct jcf_block *, 
+                              struct jcf_partial *));
+static void push_constant1 PARAMS ((HOST_WIDE_INT, struct jcf_partial *));
+static void push_constant2 PARAMS ((HOST_WIDE_INT, struct jcf_partial *));
+static void push_int_const PARAMS ((HOST_WIDE_INT, struct jcf_partial *));
+static int find_constant_wide PARAMS ((HOST_WIDE_INT, HOST_WIDE_INT,
+                                     struct jcf_partial *));
+static void push_long_const PARAMS ((HOST_WIDE_INT, HOST_WIDE_INT, 
+                                   struct jcf_partial *));
+static int find_constant_index PARAMS ((tree, struct jcf_partial *));
+static void push_long_const PARAMS ((HOST_WIDE_INT, HOST_WIDE_INT,
+                                   struct jcf_partial *));
+static void field_op PARAMS ((tree, int, struct jcf_partial *));
+static void maybe_wide PARAMS ((int, int, struct jcf_partial *));
+static void emit_dup PARAMS ((int, int, struct jcf_partial *));
+static void emit_pop PARAMS ((int, struct jcf_partial *));
+static void emit_load_or_store PARAMS ((tree, int, struct jcf_partial *));
+static void emit_load PARAMS ((tree, struct jcf_partial *));
+static void emit_store PARAMS ((tree, struct jcf_partial *));
+static void emit_unop PARAMS ((enum java_opcode, tree, struct jcf_partial *));
+static void emit_binop PARAMS ((enum java_opcode, tree, struct jcf_partial *));
+static void emit_reloc PARAMS ((HOST_WIDE_INT, int, struct jcf_block *,
+                              struct jcf_partial *));
+static void emit_switch_reloc PARAMS ((struct jcf_block *,
+                                     struct jcf_partial *));
+static void emit_case_reloc PARAMS ((struct jcf_relocation *,
+                                   struct jcf_partial *));
+static void emit_if PARAMS ((struct jcf_block *, int, int,
+                           struct jcf_partial *));
+static void emit_goto PARAMS ((struct jcf_block *, struct jcf_partial *));
+static void emit_jsr PARAMS ((struct jcf_block *, struct jcf_partial *));
+static void call_cleanups PARAMS ((struct jcf_block *, struct jcf_partial *));
+static char *make_class_file_name PARAMS ((tree));
 
 /* Utility macros for appending (big-endian) data to a buffer.
    We assume a local variable 'ptr' points into where we want to
@@ -298,12 +361,19 @@ CHECK_PUT(ptr, state, i)
 #define PUT4(X)  (PUT2((X) >> 16), PUT2((X) & 0xFFFF))
 #define PUTN(P, N)  (CHECK_PUT(ptr, state, N), memcpy(ptr, P, N), ptr += (N))
 
+/* There are some cases below where CHECK_PUT is guaranteed to fail.
+   Use the following macros in those specific cases.  */
+#define UNSAFE_PUT1(X)  (*ptr++ = (X))
+#define UNSAFE_PUT2(X)  (UNSAFE_PUT1((X) >> 8), UNSAFE_PUT1((X) & 0xFF))
+#define UNSAFE_PUT4(X)  (UNSAFE_PUT2((X) >> 16), UNSAFE_PUT2((X) & 0xFFFF))
+#define UNSAFE_PUTN(P, N)  (memcpy(ptr, P, N), ptr += (N))
+
 \f
 /* Allocate a new chunk on obstack WORK, and link it in after LAST.
    Set the data and size fields to DATA and SIZE, respectively.
    However, if DATA is NULL and SIZE>0, allocate a buffer as well. */
 
-struct chunk *
+static struct chunk *
 alloc_chunk (last, data, size, work)
      struct chunk *last;
      unsigned char *data;
@@ -338,7 +408,7 @@ CHECK_OP(struct jcf_partial *state)
 #define CHECK_OP(STATE) ((void)0)
 #endif
 
-unsigned char *
+static unsigned char *
 append_chunk (data, size, state)
      unsigned char *data;
      int size;
@@ -350,7 +420,7 @@ append_chunk (data, size, state)
   return state->chunk->data;
 }
 
-void
+static void
 append_chunk_copy (data, size, state)
      unsigned char *data;
      int size;
@@ -360,7 +430,7 @@ append_chunk_copy (data, size, state)
   memcpy (ptr, data, size);
 }
 \f
-struct jcf_block *
+static struct jcf_block *
 gen_jcf_label (state)
      struct jcf_partial *state;
 {
@@ -372,7 +442,7 @@ gen_jcf_label (state)
   return block;
 }
 
-void
+static void
 finish_jcf_block (state)
      struct jcf_partial *state;
 {
@@ -399,7 +469,7 @@ finish_jcf_block (state)
   state->code_length = pc;
 }
 
-void
+static void
 define_jcf_label (label, state)
      struct jcf_block *label;
      struct jcf_partial *state;
@@ -416,7 +486,7 @@ define_jcf_label (label, state)
   label->u.relocations = NULL;
 }
 
-struct jcf_block *
+static struct jcf_block *
 get_jcf_label_here (state)
      struct jcf_partial *state;
 {
@@ -432,7 +502,7 @@ get_jcf_label_here (state)
 
 /* Note a line number entry for the current PC and given LINE. */
 
-void
+static void
 put_linenumber (line, state)
      int line;
      struct jcf_partial *state;
@@ -492,7 +562,7 @@ struct localvar_info
 #define localvar_max \
   ((struct localvar_info**) state->localvars.ptr - localvar_buffer)
 
-void
+static void
 localvar_alloc (decl, state)
      tree decl;
      struct jcf_partial *state;
@@ -525,7 +595,8 @@ localvar_alloc (decl, state)
   info->decl = decl;
   info->start_label = start_label;
 
-  if (DECL_NAME (decl) != NULL_TREE)
+  if (debug_info_level > DINFO_LEVEL_TERSE
+      && DECL_NAME (decl) != NULL_TREE)
     {
       /* Generate debugging info. */
       info->next = NULL;
@@ -538,7 +609,7 @@ localvar_alloc (decl, state)
     }
 }
 
-int
+static void
 localvar_free (decl, state)
      tree decl;     
      struct jcf_partial *state;
@@ -569,7 +640,7 @@ localvar_free (decl, state)
 /* Get the access flags of a class (TYPE_DECL), a method (FUNCTION_DECL), or
    a field (FIELD_DECL or VAR_DECL, if static), as encoded in a .class file. */
 
-int
+static int
 get_access_flags (decl)
     tree decl;
 {
@@ -622,7 +693,7 @@ get_access_flags (decl)
 
 /* Write the list of segments starting at CHUNKS to STREAM. */
 
-void
+static void
 write_chunks (stream, chunks)
      FILE* stream;
      struct chunk *chunks;
@@ -636,7 +707,7 @@ write_chunks (stream, chunks)
 
 static void
 push_constant1 (index, state)
-     int index;
+     HOST_WIDE_INT index;
      struct jcf_partial *state;
 {
   RESERVE (3);
@@ -657,7 +728,7 @@ push_constant1 (index, state)
 
 static void
 push_constant2 (index, state)
-     int index;
+     HOST_WIDE_INT index;
      struct jcf_partial *state;
 {
   RESERVE (3);
@@ -688,7 +759,8 @@ push_int_const (i, state)
     }
   else
     {
-      i = find_constant1 (&state->cpool, CONSTANT_Integer, i & 0xFFFFFFFF);
+      i = find_constant1 (&state->cpool, CONSTANT_Integer, 
+                         (jword)(i & 0xFFFFFFFF));
       push_constant1 (i, state);
     }
 }
@@ -701,7 +773,7 @@ find_constant_wide (lo, hi, state)
   HOST_WIDE_INT w1, w2;
   lshift_double (lo, hi, -32, 64, &w1, &w2, 1);
   return find_constant2 (&state->cpool, CONSTANT_Long,
-                        w1 & 0xFFFFFFFF, lo & 0xFFFFFFFF);
+                        (jword)(w1 & 0xFFFFFFFF), (jword)(lo & 0xFFFFFFFF));
 }
 
 /* Find or allocate a constant pool entry for the given VALUE.
@@ -716,7 +788,7 @@ find_constant_index (value, state)
     {
       if (TYPE_PRECISION (TREE_TYPE (value)) <= 32)
        return find_constant1 (&state->cpool, CONSTANT_Integer,
-                              TREE_INT_CST_LOW (value) & 0xFFFFFFFF);
+                              (jword)(TREE_INT_CST_LOW (value) & 0xFFFFFFFF));
       else
        return find_constant_wide (TREE_INT_CST_LOW (value),
                                   TREE_INT_CST_HIGH (value), state);
@@ -727,14 +799,17 @@ find_constant_index (value, state)
       if (TYPE_PRECISION (TREE_TYPE (value)) == 32)
        {
          words[0] = etarsingle (TREE_REAL_CST (value)) & 0xFFFFFFFF;
-         return find_constant1 (&state->cpool, CONSTANT_Float, words[0]);
+         return find_constant1 (&state->cpool, CONSTANT_Float, 
+                                (jword)words[0]);
        }
       else
        {
          etardouble (TREE_REAL_CST (value), words);
          return find_constant2 (&state->cpool, CONSTANT_Double,
-                                words[1-FLOAT_WORDS_BIG_ENDIAN] & 0xFFFFFFFF,
-                                words[FLOAT_WORDS_BIG_ENDIAN] & 0xFFFFFFFF);
+                                (jword)(words[1-FLOAT_WORDS_BIG_ENDIAN] & 
+                                        0xFFFFFFFF),
+                                (jword)(words[FLOAT_WORDS_BIG_ENDIAN] & 
+                                        0xFFFFFFFF));
        }
     }
   else if (TREE_CODE (value) == STRING_CST)
@@ -784,7 +859,7 @@ field_op (field, opcode, state)
    reference) to 7 (for 'short') which matches the pattern of how JVM
    opcodes typically depend on the operand type. */
 
-int
+static int
 adjust_typed_op (type, max)
      tree type;
      int max;
@@ -877,7 +952,7 @@ emit_pop (size, state)
 static void
 emit_iinc (var, value, state)
      tree var;
-     int value;
+     HOST_WIDE_INT value;
      struct jcf_partial *state;
 {
   int slot = DECL_LOCAL_INDEX (var);
@@ -938,7 +1013,7 @@ emit_store (var, state)
 static void
 emit_unop (opcode, type, state)
      enum java_opcode opcode;
-     tree type;
+     tree type ATTRIBUTE_UNUSED;
      struct jcf_partial *state;
 {
   RESERVE(1);
@@ -983,7 +1058,7 @@ emit_switch_reloc (label, state)
      struct jcf_block *label;
      struct jcf_partial *state;
 {
-  emit_reloc (0, BLOCK_START_RELOC, label, state);
+  emit_reloc (RELOCATION_VALUE_0, BLOCK_START_RELOC, label, state);
 }
 
 /* Similar to emit_switch_reloc,
@@ -1012,8 +1087,8 @@ emit_if (target, opcode, inv_opcode, state)
      struct jcf_partial *state;
 {
   OP1 (opcode);
-  // value is 1 byte from reloc back to start of instruction.
-  emit_reloc (1, - inv_opcode, target, state);
+  /* value is 1 byte from reloc back to start of instruction.  */
+  emit_reloc (RELOCATION_VALUE_1, - inv_opcode, target, state);
 }
 
 static void
@@ -1022,8 +1097,8 @@ emit_goto (target, state)
      struct jcf_partial *state;
 {
   OP1 (OPCODE_goto);
- // Value is 1 byte from reloc back to start of instruction.
-  emit_reloc (1, OPCODE_goto_w, target, state);
+  /* Value is 1 byte from reloc back to start of instruction.  */
+  emit_reloc (RELOCATION_VALUE_1, OPCODE_goto_w, target, state);
 }
 
 static void
@@ -1032,8 +1107,8 @@ emit_jsr (target, state)
      struct jcf_partial *state;
 {
   OP1 (OPCODE_jsr);
- // Value is 1 byte from reloc back to start of instruction.
-  emit_reloc (1, OPCODE_jsr_w, target, state);
+  /* Value is 1 byte from reloc back to start of instruction.  */
+  emit_reloc (RELOCATION_VALUE_1, OPCODE_jsr_w, target, state);
 }
 
 /* Generate code to evaluate EXP.  If the result is true,
@@ -1042,7 +1117,7 @@ emit_jsr (target, state)
    TRUE_LABEL may follow right after this. (The idea is that we
    may be able to optimize away GOTO TRUE_LABEL; TRUE_LABEL:) */
 
-void
+static void
 generate_bytecode_conditional (exp, true_label, false_label,
                               true_branch_first, state)
      tree exp;
@@ -1081,7 +1156,8 @@ generate_bytecode_conditional (exp, true_label, false_label,
       }
       break;
     case TRUTH_NOT_EXPR:
-      generate_bytecode_conditional (TREE_OPERAND (exp, 0), false_label, true_label,
+      generate_bytecode_conditional (TREE_OPERAND (exp, 0), 
+                                    false_label, true_label,
                                     ! true_branch_first, state);
       break;
     case TRUTH_ANDIF_EXPR:
@@ -1159,7 +1235,7 @@ generate_bytecode_conditional (exp, true_label, false_label,
            }
          if (integer_zerop (exp1) || integer_zerop (exp0))
            {
-             generate_bytecode_insns (integer_zerop (exp1) ? exp0 : exp0,
+             generate_bytecode_insns (integer_zerop (exp1) ? exp0 : exp1,
                                       STACK_TARGET, state);
              op = op + (OPCODE_ifnull - OPCODE_if_acmpeq);
              negop = (op & 1) ? op - 1 : op + 1;
@@ -1266,6 +1342,72 @@ call_cleanups (limit, state)
     }
 }
 
+static void
+generate_bytecode_return (exp, state)
+     tree exp;
+     struct jcf_partial *state;
+{
+  tree return_type = TREE_TYPE (TREE_TYPE (state->current_method));
+  int returns_void = TREE_CODE (return_type) == VOID_TYPE;
+  int op;
+ again:
+  if (exp != NULL)
+    {
+      switch (TREE_CODE (exp))
+       {
+       case COMPOUND_EXPR:     
+         generate_bytecode_insns (TREE_OPERAND (exp, 0), IGNORE_TARGET,
+                                  state);
+         exp = TREE_OPERAND (exp, 1);
+         goto again;
+       case COND_EXPR:
+         {
+           struct jcf_block *then_label = gen_jcf_label (state);
+           struct jcf_block *else_label = gen_jcf_label (state);
+           generate_bytecode_conditional (TREE_OPERAND (exp, 0),
+                                          then_label, else_label, 1, state);
+           define_jcf_label (then_label, state);
+           generate_bytecode_return (TREE_OPERAND (exp, 1), state);
+           define_jcf_label (else_label, state);
+           generate_bytecode_return (TREE_OPERAND (exp, 2), state);
+         }
+         return;
+       default:
+         generate_bytecode_insns (exp,
+                                  returns_void ? IGNORE_TARGET
+                                  : STACK_TARGET, state);
+       }
+    }
+  if (returns_void)
+    {
+      op = OPCODE_return;
+      call_cleanups (NULL_PTR, state);
+    }
+  else
+    {
+      op = OPCODE_ireturn + adjust_typed_op (return_type, 4);
+      if (state->num_finalizers > 0)
+       {
+         if (state->return_value_decl == NULL_TREE)
+           {
+             state->return_value_decl
+               = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (exp));
+             localvar_alloc (state->return_value_decl, state);
+           }
+         emit_store (state->return_value_decl, state);
+         call_cleanups (NULL_PTR, state);
+         emit_load (state->return_value_decl, state);
+         /* If we call localvar_free (state->return_value_decl, state),
+            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
+            the greatest solution, but it is at least simple and safe. */
+       }
+    }
+  RESERVE (1);
+  OP1 (op);
+}
+
 /* Generate bytecode for sub-expression EXP of METHOD.
    TARGET is one of STACK_TARGET or IGNORE_TARGET. */
 
@@ -1317,8 +1459,8 @@ generate_bytecode_insns (exp, target, state)
        }
       break;
       case COMPOUND_EXPR:      
-       generate_bytecode_insns (TREE_OPERAND (exp, 0), IGNORE_TARGET, state);
-       generate_bytecode_insns (TREE_OPERAND (exp, 1), target, state);
+      generate_bytecode_insns (TREE_OPERAND (exp, 0), IGNORE_TARGET, state);
+      generate_bytecode_insns (TREE_OPERAND (exp, 1), target, state);
       break;
     case EXPR_WITH_FILE_LOCATION:
       {
@@ -1329,7 +1471,8 @@ generate_bytecode_insns (exp, target, state)
          break;
        input_filename = EXPR_WFL_FILENAME (exp);
        lineno = EXPR_WFL_LINENO (exp);
-       if (EXPR_WFL_EMIT_LINE_NOTE (exp) && lineno > 0)
+       if (EXPR_WFL_EMIT_LINE_NOTE (exp) && lineno > 0
+           && debug_info_level > DINFO_LEVEL_NONE)
          put_linenumber (lineno, state);
        generate_bytecode_insns (body, target, state);
        input_filename = saved_input_filename;
@@ -1359,20 +1502,26 @@ generate_bytecode_insns (exp, target, state)
        }
       break;
     case REAL_CST:
-      offset = find_constant_index (exp, state);
-      switch (TYPE_PRECISION (type))
-       {
-       case 32:
-         push_constant1 (offset, state);
-         NOTE_PUSH (1);
-         break;
-       case 64:
-         push_constant2 (offset, state);
-         NOTE_PUSH (2);
-         break;
-       default:
-         abort ();
-       }
+      {
+       int prec = TYPE_PRECISION (type) >> 5;
+       RESERVE(1);
+       if (real_zerop (exp))
+         OP1 (prec == 1 ? OPCODE_fconst_0 : OPCODE_dconst_0);
+       else if (real_onep (exp))
+         OP1 (prec == 1 ? OPCODE_fconst_1 : OPCODE_dconst_1);
+       /* FIXME Should also use fconst_2 for 2.0f.
+          Also, should use iconst_2/ldc followed by i2f/i2d
+          for other float/double when the value is a small integer. */
+       else
+         {
+           offset = find_constant_index (exp, state);
+           if (prec == 1)
+             push_constant1 (offset, state);
+           else
+             push_constant2 (offset, state);
+         }
+       NOTE_PUSH (prec);
+      }
       break;
     case STRING_CST:
       push_constant1 (find_string_constant (&state->cpool, exp), state);
@@ -1470,6 +1619,10 @@ generate_bytecode_insns (exp, target, state)
        define_jcf_label (else_label, state);
        generate_bytecode_insns (TREE_OPERAND (exp, 2), target, state);
        define_jcf_label (end_label, state);
+
+       /* COND_EXPR can be used in a binop. The stack must be adjusted. */
+       if (TREE_TYPE (exp) != void_type_node)
+         NOTE_POP (TYPE_PRECISION (TREE_TYPE (exp)) > 32 ? 2 : 1);
       }
       break;
     case CASE_EXPR:
@@ -1588,7 +1741,8 @@ generate_bytecode_insns (exp, target, state)
                int index = 0;
                RESERVE (13 + 4 * (sw_state.max_case - sw_state.min_case + 1));
                OP1 (OPCODE_tableswitch);
-               emit_reloc (0, SWITCH_ALIGN_RELOC, NULL, state);
+               emit_reloc (RELOCATION_VALUE_0, 
+                           SWITCH_ALIGN_RELOC, NULL, state);
                emit_switch_reloc (sw_state.default_label, state);
                OP4 (sw_state.min_case);
                OP4 (sw_state.max_case);
@@ -1611,7 +1765,8 @@ generate_bytecode_insns (exp, target, state)
              { /* Use lookupswitch. */
                RESERVE(9 + 8 * sw_state.num_cases);
                OP1 (OPCODE_lookupswitch);
-               emit_reloc (0, SWITCH_ALIGN_RELOC, NULL, state);
+               emit_reloc (RELOCATION_VALUE_0,
+                           SWITCH_ALIGN_RELOC, NULL, state);
                emit_switch_reloc (sw_state.default_label, state);
                OP4 (sw_state.num_cases);
                for (i = 0;  i < sw_state.num_cases;  i++)
@@ -1648,39 +1803,14 @@ generate_bytecode_insns (exp, target, state)
       }
 
     case RETURN_EXPR:
-      if (!TREE_OPERAND (exp, 0))
-       {
-         op = OPCODE_return;
-         call_cleanups (NULL_TREE, state);
-       }
+      exp = TREE_OPERAND (exp, 0);
+      if (exp == NULL_TREE)
+       exp = empty_stmt_node;
+      else if (TREE_CODE (exp) != MODIFY_EXPR) 
+       abort ();
       else
-       {
-         exp = TREE_OPERAND (exp, 0);
-         if (TREE_CODE (exp) != MODIFY_EXPR)
-           abort ();
-         exp = TREE_OPERAND (exp, 1);
-         op = OPCODE_ireturn + adjust_typed_op (TREE_TYPE (exp), 4);
-         generate_bytecode_insns (exp, STACK_TARGET, state);
-         if (state->num_finalizers > 0)
-           {
-             if (state->return_value_decl == NULL_TREE)
-               {
-                 state->return_value_decl
-                   = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (exp));
-                 localvar_alloc (state->return_value_decl, state);
-               }
-             emit_store (state->return_value_decl, state);
-             call_cleanups (NULL_TREE, state);
-             emit_load (state->return_value_decl, state);
-             /* If we call localvar_free (state->return_value_decl, state),
-                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
-                the greatest solution, but it is at least simple and safe. */
-           }
-       }
-      RESERVE (1);
-      OP1 (op);
+       exp = TREE_OPERAND (exp, 1);
+      generate_bytecode_return (exp, state);
       break;
     case LABELED_BLOCK_EXPR:
       {
@@ -1809,7 +1939,7 @@ generate_bytecode_insns (exp, target, state)
       if (size == 1)
        push_int_const (value, state);
       else
-       push_long_const (value, value >= 0 ? 0 : -1, state);
+       push_long_const (value, (HOST_WIDE_INT)(value >= 0 ? 0 : -1), state);
       NOTE_PUSH (size);
       emit_binop (OPCODE_iadd + adjust_typed_op (type, 3), type, state);
       if (target != IGNORE_TARGET && ! post_op)
@@ -1936,8 +2066,11 @@ generate_bytecode_insns (exp, target, state)
     case LSHIFT_EXPR:   jopcode = OPCODE_ishl;   goto binop;
     case RSHIFT_EXPR:   jopcode = OPCODE_ishr;   goto binop;
     case URSHIFT_EXPR:  jopcode = OPCODE_iushr;  goto binop;
+    case TRUTH_AND_EXPR:
     case BIT_AND_EXPR:  jopcode = OPCODE_iand;   goto binop;
+    case TRUTH_OR_EXPR:
     case BIT_IOR_EXPR:  jopcode = OPCODE_ior;    goto binop;
+    case TRUTH_XOR_EXPR:
     case BIT_XOR_EXPR:  jopcode = OPCODE_ixor;   goto binop;
     binop:
     {
@@ -2008,7 +2141,8 @@ generate_bytecode_insns (exp, target, state)
          {
            if (TREE_CODE (exp) == CONVERT_EXPR)
              {
-               int index = find_class_constant (&state->cpool, TREE_TYPE (dst_type));
+               int index = find_class_constant (&state->cpool, 
+                                                TREE_TYPE (dst_type));
                RESERVE (3);
                OP1 (OPCODE_checkcast);
                OP2 (index);
@@ -2129,24 +2263,17 @@ generate_bytecode_insns (exp, target, state)
     case TRY_EXPR:
       {
        tree try_clause = TREE_OPERAND (exp, 0);
-       tree finally = TREE_OPERAND (exp, 2);
        struct jcf_block *start_label = get_jcf_label_here (state);
        struct jcf_block *end_label;  /* End of try clause. */
-       struct jcf_block *finally_label;  /* Finally subroutine. */
        struct jcf_block *finished_label = gen_jcf_label (state);
        tree clause = TREE_OPERAND (exp, 1);
-       if (finally)
-         {
-           finally = FINALLY_EXPR_BLOCK (finally);
-           finally_label = gen_jcf_label (state);
-         }
        if (target != IGNORE_TARGET)
          abort ();
        generate_bytecode_insns (try_clause, IGNORE_TARGET, state);
        end_label = get_jcf_label_here (state);
        if (CAN_COMPLETE_NORMALLY (try_clause))
          emit_goto (finished_label, state);
-       for ( ; clause != NULL_TREE;  clause = TREE_CHAIN (clause))
+       while (clause != NULL_TREE)
          {
            tree catch_clause = TREE_OPERAND (clause, 0);
            tree exception_decl = BLOCK_EXPR_DECLS (catch_clause);
@@ -2156,43 +2283,63 @@ generate_bytecode_insns (exp, target, state)
            else
              handler->type = TREE_TYPE (TREE_TYPE (exception_decl));
            generate_bytecode_insns (catch_clause, IGNORE_TARGET, state);
-           if (CAN_COMPLETE_NORMALLY (catch_clause))
+           clause = TREE_CHAIN (clause);
+           if (CAN_COMPLETE_NORMALLY (catch_clause) && clause != NULL_TREE)
              emit_goto (finished_label, state);
          }
-       if (finally)
-         {
-           tree return_link;
-           tree exception_type = build_pointer_type (throwable_type_node);
-           tree exception_decl = build_decl (VAR_DECL, NULL_TREE,
-                                             exception_type);
-           struct jcf_handler *handler
-             = alloc_handler (start_label, NULL_TREE, state);
-           handler->end_label = handler->handler_label;
-           handler->type = NULL_TREE;
-           localvar_alloc (exception_decl, state);
-           NOTE_PUSH (1);
-            emit_store (exception_decl, state);
-           emit_jsr (finally_label, state);
-           emit_load (exception_decl, state);
-           RESERVE (1);
-           OP1 (OPCODE_athrow);
-           NOTE_POP (1);
-           localvar_free (exception_decl, state);
+       define_jcf_label (finished_label, state);
+      }
+      break;
+    case TRY_FINALLY_EXPR:
+      {
+       tree try_block = TREE_OPERAND (exp, 0);
+       tree finally = TREE_OPERAND (exp, 1);
+       struct jcf_block *finished_label = gen_jcf_label (state);
+       struct jcf_block *finally_label = gen_jcf_label (state);
+       struct jcf_block *start_label = get_jcf_label_here (state);
+       tree return_link = build_decl (VAR_DECL, NULL_TREE,
+                                      return_address_type_node);
+       tree exception_type = build_pointer_type (throwable_type_node);
+       tree exception_decl = build_decl (VAR_DECL, NULL_TREE, exception_type);
+       struct jcf_handler *handler;
+
+       finally_label->pc = PENDING_CLEANUP_PC;
+       finally_label->next = state->labeled_blocks;
+       state->labeled_blocks = finally_label;
+       state->num_finalizers++;
 
-           /* The finally block. */
-           return_link = build_decl (VAR_DECL, NULL_TREE,
-                                     return_address_type_node);
-           define_jcf_label (finally_label, state);
-           NOTE_PUSH (1);
-           localvar_alloc (return_link, state);
-           emit_store (return_link, state);
-           generate_bytecode_insns (finally, IGNORE_TARGET, state);
-           maybe_wide (OPCODE_ret, DECL_LOCAL_INDEX (return_link), state);
-           localvar_free (return_link, state);
-         }
+       generate_bytecode_insns (try_block, target, state);
+       if (state->labeled_blocks != finally_label)
+         abort();
+       state->labeled_blocks = finally_label->next;
+       emit_jsr (finally_label, state);
+       if (CAN_COMPLETE_NORMALLY (try_block))
+         emit_goto (finished_label, state);
+
+       /* Handle exceptions. */
+       localvar_alloc (return_link, state);
+       handler = alloc_handler (start_label, NULL_PTR, state);
+       handler->end_label = handler->handler_label;
+       handler->type = NULL_TREE;
+       localvar_alloc (exception_decl, state);
+       NOTE_PUSH (1);
+       emit_store (exception_decl, state);
+       emit_jsr (finally_label, state);
+       emit_load (exception_decl, state);
+       RESERVE (1);
+       OP1 (OPCODE_athrow);
+       NOTE_POP (1);
+       localvar_free (exception_decl, state);
+
+       /* The finally block.  First save return PC into return_link. */
+       define_jcf_label (finally_label, state);
+       NOTE_PUSH (1);
+       emit_store (return_link, state);
+
+       generate_bytecode_insns (finally, IGNORE_TARGET, state);
+       maybe_wide (OPCODE_ret, DECL_LOCAL_INDEX (return_link), state);
+       localvar_free (return_link, state);
        define_jcf_label (finished_label, state);
-       if (finally)
-         emit_jsr (finally_label, state);
       }
       break;
     case THROW_EXPR:
@@ -2305,7 +2452,8 @@ generate_bytecode_insns (exp, target, state)
          }
        else if (f == soft_monitorenter_node
                 || f == soft_monitorexit_node
-                || f == throw_node)
+                || f == throw_node[0]
+                || f == throw_node[1])
          {
            if (f == soft_monitorenter_node)
              op = OPCODE_monitorenter;
@@ -2330,6 +2478,13 @@ generate_bytecode_insns (exp, target, state)
          }
        nargs = state->code_SP - save_SP;
        state->code_SP = save_SP;
+       if (f == soft_fmod_node)
+         {
+           RESERVE (1);
+           OP1 (OPCODE_drem);
+           NOTE_PUSH (2);
+           break;
+         }
        if (TREE_CODE (exp) == NEW_CLASS_EXPR)
          NOTE_POP (1);  /* Pop implicit this. */
        if (TREE_CODE (f) == FUNCTION_DECL && DECL_CONTEXT (f) != NULL_TREE)
@@ -2350,6 +2505,11 @@ generate_bytecode_insns (exp, target, state)
            else
              OP1 (OPCODE_invokevirtual);
            OP2 (index);
+           if (interface)
+             {
+               OP1 (nargs);
+               OP1 (0);
+             }
            f = TREE_TYPE (TREE_TYPE (f));
            if (TREE_CODE (f) != VOID_TYPE)
              {
@@ -2359,11 +2519,6 @@ generate_bytecode_insns (exp, target, state)
                else
                  NOTE_PUSH (size);
              }
-           if (interface)
-             {
-               OP1 (nargs);
-               OP1 (0);
-             }
            break;
          }
       }
@@ -2375,7 +2530,7 @@ generate_bytecode_insns (exp, target, state)
     }
 }
 
-void
+static void
 perform_relocations (state)
      struct jcf_partial *state;
 {
@@ -2543,7 +2698,7 @@ perform_relocations (state)
   state->code_length = pc;
 }
 
-void
+static void
 init_jcf_state (state, work)
      struct jcf_partial *state;
      struct obstack *work;
@@ -2555,7 +2710,7 @@ init_jcf_state (state, work)
   BUFFER_INIT (&state->bytecode);
 }
 
-void
+static void
 init_jcf_method (state, method)
      struct jcf_partial *state;
      tree method;
@@ -2578,7 +2733,7 @@ init_jcf_method (state, method)
   state->return_value_decl = NULL_TREE;
 }
 
-void
+static void
 release_jcf_state (state)
      struct jcf_partial *state;
 {
@@ -2590,7 +2745,7 @@ release_jcf_state (state)
    in the .class file representation.  The list can be written to a
    .class file using write_chunks.  Allocate chunks from obstack WORK. */
 
-struct chunk *
+static struct chunk *
 generate_classfile (clas, state)
      tree clas;
      struct jcf_partial *state;
@@ -2623,7 +2778,9 @@ generate_classfile (clas, state)
   else
     i = 8 + 2 * total_supers;
   ptr = append_chunk (NULL, i, state);
-  i = get_access_flags (TYPE_NAME (clas)) | ACC_SUPER;
+  i = get_access_flags (TYPE_NAME (clas));
+  if (! (i & ACC_INTERFACE))
+    i |= ACC_SUPER;
   PUT2 (i); /* acces_flags */
   i = find_class_constant (&state->cpool, clas);  PUT2 (i);  /* this_class */
   if (clas == object_type_node)
@@ -2673,7 +2830,7 @@ generate_classfile (clas, state)
        }
       fields_count++;
     }
-  ptr = fields_count_ptr;  PUT2 (fields_count);
+  ptr = fields_count_ptr;  UNSAFE_PUT2 (fields_count);
 
   ptr = methods_count_ptr = append_chunk (NULL, 2, state);
   PUT2 (0);
@@ -2694,7 +2851,8 @@ generate_classfile (clas, state)
       i = find_utf8_constant (&state->cpool, name);  PUT2 (i);
       i = find_utf8_constant (&state->cpool, build_java_signature (type));
       PUT2 (i);
-      PUT2 (body != NULL_TREE ? 1 : 0);   /* attributes_count */
+      i = (body != NULL_TREE) + (DECL_FUNCTION_THROWS (part) != NULL_TREE);
+      PUT2 (i);   /* attributes_count */
       if (body != NULL_TREE)
        {
          int code_attributes_count = 0;
@@ -2738,10 +2896,10 @@ generate_classfile (clas, state)
              code_attributes_count++;
              i += 8 + 10 * state->lvar_count;
            }
-         PUT4 (i); /* attribute_length */
-         PUT2 (state->code_SP_max);  /* max_stack */
-         PUT2 (localvar_max);  /* max_locals */
-         PUT4 (state->code_length);
+         UNSAFE_PUT4 (i); /* attribute_length */
+         UNSAFE_PUT2 (state->code_SP_max);  /* max_stack */
+         UNSAFE_PUT2 (localvar_max);  /* max_locals */
+         UNSAFE_PUT4 (state->code_length);
 
          /* Emit the exception table. */
          ptr = append_chunk (NULL, 2 + 8 * state->num_handlers, state);
@@ -2810,10 +2968,28 @@ generate_classfile (clas, state)
                }
            }
        }
+      if (DECL_FUNCTION_THROWS (part) != NULL_TREE)
+       {
+         tree t = DECL_FUNCTION_THROWS (part);
+         int throws_count = list_length (t);
+         static tree Exceptions_node = NULL_TREE;
+         if (Exceptions_node == NULL_TREE)
+           Exceptions_node = get_identifier ("Exceptions");
+         ptr = append_chunk (NULL, 8 + 2 * throws_count, state);
+         i = find_utf8_constant (&state->cpool, Exceptions_node);
+         PUT2 (i);  /* attribute_name_index */ 
+         i = 2 + 2 * throws_count;  PUT4(i); /* attribute_length */ 
+         i = throws_count;  PUT2 (i); 
+         for (;  t != NULL_TREE;  t = TREE_CHAIN (t))
+           {
+             i = find_class_constant (&state->cpool, TREE_VALUE (t));
+             PUT2 (i);
+           }
+       }
       methods_count++;
       current_function_decl = save_function;
     }
-  ptr = methods_count_ptr;  PUT2 (methods_count);
+  ptr = methods_count_ptr;  UNSAFE_PUT2 (methods_count);
 
   source_file = DECL_SOURCE_FILE (TYPE_NAME (clas));
   for (ptr = source_file;  ;  ptr++)
@@ -2849,7 +3025,8 @@ static char *
 make_class_file_name (clas)
      tree clas;
 {
-  char *cname, *dname, *slash, *r;
+  const char *dname, *slash;
+  char *cname, *r;
   struct stat sb;
 
   cname = IDENTIFIER_POINTER (identifier_subst (DECL_NAME (TYPE_NAME (clas)),
This page took 0.060016 seconds and 5 git commands to generate.