OSDN Git Service

PR fortran/19754
[pf3gnuchains/gcc-fork.git] / gcc / java / jcf-write.c
index d9fc650..8779040 100644 (file)
@@ -1,5 +1,5 @@
 /* Write out a Java(TM) class file.
-   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
+   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -40,16 +40,12 @@ The Free Software Foundation is independent of Sun Microsystems, Inc.  */
 #include "ggc.h"
 #include "tm_p.h"
 
-#ifndef DIR_SEPARATOR
-#define DIR_SEPARATOR '/'
-#endif
-
 extern struct obstack temporary_obstack;
 
 /* Base directory in which `.class' files should be written.
    NULL means to put the file into the same directory as the
    corresponding .java file.  */
-char *jcf_write_base_directory = NULL;
+const char *jcf_write_base_directory = NULL;
 
 /* Make sure bytecode.data is big enough for at least N more bytes. */
 
@@ -279,6 +275,9 @@ struct jcf_partial
 
   /* Information about the current switch statement. */
   struct jcf_switch_state *sw_state;
+
+  /* The count of jsr instructions that have been emitted.  */
+  long num_jsrs;
 };
 
 static void generate_bytecode_insns (tree, int, struct jcf_partial *);
@@ -293,7 +292,7 @@ static void define_jcf_label (struct jcf_block *, struct jcf_partial *);
 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);
@@ -305,6 +304,7 @@ static void perform_relocations (struct jcf_partial *);
 static void init_jcf_state (struct jcf_partial *, struct obstack *);
 static void init_jcf_method (struct jcf_partial *, tree);
 static void release_jcf_state (struct jcf_partial *);
+static int get_classfile_modifiers (tree class);
 static struct chunk * generate_classfile (tree, struct jcf_partial *);
 static struct jcf_handler *alloc_handler (struct jcf_block *,
                                          struct jcf_block *,
@@ -387,8 +387,7 @@ static struct chunk *
 alloc_chunk (struct chunk *last, unsigned char *data,
             int size, struct obstack *work)
 {
-  struct chunk *chunk = (struct chunk *)
-    obstack_alloc (work, sizeof(struct chunk));
+  struct chunk *chunk = obstack_alloc (work, sizeof(struct chunk));
 
   if (data == NULL && size > 0)
     data = obstack_alloc (work, size);
@@ -435,8 +434,8 @@ append_chunk_copy (unsigned char *data, int size, struct jcf_partial *state)
 static struct jcf_block *
 gen_jcf_label (struct jcf_partial *state)
 {
-  struct jcf_block *block = (struct jcf_block *)
-    obstack_alloc (state->chunk_obstack, sizeof (struct jcf_block));
+  struct jcf_block *block
+    obstack_alloc (state->chunk_obstack, sizeof (struct jcf_block));
   block->next =        NULL;
   block->linenumber = -1;
   block->pc = UNDEFINED_PC;
@@ -519,8 +518,8 @@ static struct jcf_handler *
 alloc_handler (struct jcf_block *start_label, struct jcf_block *end_label,
               struct jcf_partial *state)
 {
-  struct jcf_handler *handler = (struct jcf_handler *)
-    obstack_alloc (state->chunk_obstack, sizeof (struct jcf_handler));
+  struct jcf_handler *handler
+    obstack_alloc (state->chunk_obstack, sizeof (struct jcf_handler));
   handler->start_label = start_label;
   handler->end_label = end_label;
   handler->handler_label = get_jcf_label_here (state);
@@ -561,9 +560,9 @@ localvar_alloc (tree decl, struct jcf_partial *state)
   struct jcf_block *start_label = get_jcf_label_here (state);
   int wide = TYPE_IS_WIDE (TREE_TYPE (decl));
   int index;
-  register struct localvar_info *info;
-  register struct localvar_info **ptr = localvar_buffer;
-  register struct localvar_info **limit
+  struct localvar_info *info;
+  struct localvar_info **ptr = localvar_buffer;
+  struct localvar_info **limit
     = (struct localvar_info**) state->localvars.ptr;
   for (index = 0;  ptr < limit;  index++, ptr++)
     {
@@ -577,8 +576,7 @@ localvar_alloc (tree decl, struct jcf_partial *state)
       ptr = (struct localvar_info**) state->localvars.data + index;
       state->localvars.ptr = (unsigned char *) (ptr + 1 + wide);
     }
-  info = (struct localvar_info *)
-    obstack_alloc (state->chunk_obstack, sizeof (struct localvar_info));
+  info = obstack_alloc (state->chunk_obstack, sizeof (struct localvar_info));
   ptr[0] = info;
   if (wide)
     ptr[1] = (struct localvar_info *)(~0);
@@ -601,18 +599,20 @@ localvar_alloc (tree decl, struct jcf_partial *state)
 }
 
 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);
-  register struct localvar_info **ptr = &localvar_buffer [index];
-  register struct localvar_info *info = *ptr;
+  struct localvar_info **ptr = &localvar_buffer [index];
+  struct localvar_info *info = *ptr;
   int wide = TYPE_IS_WIDE (TREE_TYPE (decl));
 
   info->end_label = end_label;
 
   if (info->decl != decl)
     abort ();
+  if (! really)
+    return;
   ptr[0] = NULL;
   if (wide)
     {
@@ -634,10 +634,7 @@ get_access_flags (tree decl)
 {
   int flags = 0;
   int isfield = TREE_CODE (decl) == FIELD_DECL || TREE_CODE (decl) == VAR_DECL;
-  if (CLASS_PUBLIC (decl))  /* same as FIELD_PUBLIC and METHOD_PUBLIC */
-    flags |= ACC_PUBLIC;
-  if (CLASS_FINAL (decl))  /* same as FIELD_FINAL and METHOD_FINAL */
-    flags |= ACC_FINAL;
+
   if (isfield || TREE_CODE (decl) == FUNCTION_DECL)
     {
       if (TREE_PROTECTED (decl))
@@ -647,6 +644,10 @@ get_access_flags (tree decl)
     }
   else if (TREE_CODE (decl) == TYPE_DECL)
     {
+      if (CLASS_PUBLIC (decl))
+       flags |= ACC_PUBLIC;
+      if (CLASS_FINAL (decl))
+       flags |= ACC_FINAL;
       if (CLASS_SUPER (decl))
        flags |= ACC_SUPER;
       if (CLASS_ABSTRACT (decl))
@@ -670,6 +671,10 @@ get_access_flags (tree decl)
 
   if (TREE_CODE (decl) == FUNCTION_DECL)
     {
+      if (METHOD_PUBLIC (decl))
+       flags |= ACC_PUBLIC;
+      if (METHOD_FINAL (decl))
+       flags |= ACC_FINAL;
       if (METHOD_NATIVE (decl))
        flags |= ACC_NATIVE;
       if (METHOD_STATIC (decl))
@@ -683,6 +688,10 @@ get_access_flags (tree decl)
     }
   if (isfield)
     {
+      if (FIELD_PUBLIC (decl))
+       flags |= ACC_PUBLIC;
+      if (FIELD_FINAL (decl))
+       flags |= ACC_FINAL;
       if (FIELD_STATIC (decl))
        flags |= ACC_STATIC;
       if (FIELD_VOLATILE (decl))
@@ -763,7 +772,8 @@ static int
 find_constant_wide (HOST_WIDE_INT lo, HOST_WIDE_INT hi,
                    struct jcf_partial *state)
 {
-  HOST_WIDE_INT w1, w2;
+  unsigned HOST_WIDE_INT w1;
+  HOST_WIDE_INT w2;
   lshift_double (lo, hi, -32, 64, &w1, &w2, 1);
   return find_constant2 (&state->cpool, CONSTANT_Long,
                         (jword)(w1 & 0xFFFFFFFF), (jword)(lo & 0xFFFFFFFF));
@@ -788,6 +798,19 @@ find_constant_index (tree value, struct jcf_partial *state)
     {
       long words[2];
 
+      /* IEEE NaN can have many values, but the Java VM spec defines a
+        canonical NaN.  */      
+      if (flag_emit_class_files
+         && REAL_VALUE_ISNAN (TREE_REAL_CST (value)))
+       {
+         if (TYPE_PRECISION (TREE_TYPE (value)) == 32)
+           return find_constant1 (&state->cpool, CONSTANT_Float,
+                                  0x7fc00000);
+         else
+           return find_constant2 (&state->cpool, CONSTANT_Double,
+                                  0x7ff80000, 0x00000000);
+       }           
+      
       real_to_target (words, &TREE_REAL_CST (value),
                      TYPE_MODE (TREE_TYPE (value)));
       words[0] &= 0xffffffff;
@@ -813,7 +836,8 @@ find_constant_index (tree value, struct jcf_partial *state)
 static void
 push_long_const (HOST_WIDE_INT lo, HOST_WIDE_INT hi, struct jcf_partial *state)
 {
-  HOST_WIDE_INT highpart, dummy;
+  unsigned HOST_WIDE_INT highpart;
+  HOST_WIDE_INT dummy;
   jint lowpart = WORD_TO_INT (lo);
 
   rshift_double (lo, hi, 32, 64, &highpart, &dummy, 1);
@@ -824,7 +848,8 @@ push_long_const (HOST_WIDE_INT lo, HOST_WIDE_INT hi, struct jcf_partial *state)
       OP1(OPCODE_lconst_0 + lowpart);
     }
   else if ((highpart == 0 && lowpart > 0 && lowpart < 32768) 
-          || (highpart == -1 && lowpart < 0 && lowpart >= -32768))
+          || (highpart == (unsigned HOST_WIDE_INT)-1
+              && lowpart < 0 && lowpart >= -32768))
       {
         push_int_const (lowpart, state);
         RESERVE (1);
@@ -1003,8 +1028,8 @@ static void
 emit_reloc (HOST_WIDE_INT value, int kind,
            struct jcf_block *target, struct jcf_partial *state)
 {
-  struct jcf_relocation *reloc = (struct jcf_relocation *)
-    obstack_alloc (state->chunk_obstack, sizeof (struct jcf_relocation));
+  struct jcf_relocation *reloc
+    obstack_alloc (state->chunk_obstack, sizeof (struct jcf_relocation));
   struct jcf_block *block = state->last_block;
   reloc->next = block->u.relocations;
   block->u.relocations = reloc;
@@ -1066,6 +1091,7 @@ emit_jsr (struct jcf_block *target, struct jcf_partial *state)
   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,
@@ -1084,6 +1110,8 @@ generate_bytecode_conditional (tree exp,
   tree exp0, exp1, type;
   int save_SP = state->code_SP;
   enum java_opcode op, negop;
+  bool unordered = 0;
+  
   switch (TREE_CODE (exp))
     {
     case INTEGER_CST:
@@ -1155,25 +1183,55 @@ generate_bytecode_conditional (tree exp,
          emit_goto (false_label, state);
        }
       break;
+
+    case UNEQ_EXPR:
+      unordered = 1;
     case EQ_EXPR:
       op = OPCODE_if_icmpeq;
       goto compare;
+
+    case LTGT_EXPR:
+      unordered = 1;
     case NE_EXPR:
       op = OPCODE_if_icmpne;
       goto compare;
+
+    case UNLE_EXPR:
+      unordered = 1;
     case GT_EXPR:
       op = OPCODE_if_icmpgt;
       goto compare;
+
+    case UNGE_EXPR:
+      unordered = 1;
     case LT_EXPR:
       op = OPCODE_if_icmplt;
       goto compare;
+
+    case UNLT_EXPR:
+      unordered = 1;
     case GE_EXPR:
       op = OPCODE_if_icmpge;
       goto compare;
+
+    case UNGT_EXPR:
+      unordered = 1;
     case LE_EXPR:
       op = OPCODE_if_icmple;
       goto compare;
+
     compare:
+      if (unordered)
+        {
+         /* UNLT_EXPR(a, b) means 'a < b || unordered(a, b)'.  This is 
+         the same as the Java source expression '!(a >= b)', so handle 
+         it that way.  */
+         struct jcf_block *tmp = true_label;
+         true_label = false_label;
+         false_label = tmp;
+          true_branch_first = !true_branch_first;
+       }
+       
       exp0 = TREE_OPERAND (exp, 0);
       exp1 = TREE_OPERAND (exp, 1);
       type = TREE_TYPE (exp0);
@@ -1347,7 +1405,7 @@ generate_bytecode_return (tree exp, struct jcf_partial *state)
          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
@@ -1384,6 +1442,7 @@ generate_bytecode_insns (tree exp, int target, struct jcf_partial *state)
        {
          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);
@@ -1397,10 +1456,11 @@ generate_bytecode_insns (tree exp, int target, struct jcf_partial *state)
              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;
            }
        }
@@ -1415,19 +1475,21 @@ generate_bytecode_insns (tree exp, int target, struct jcf_partial *state)
       break;
     case EXPR_WITH_FILE_LOCATION:
       {
-       const char *saved_input_filename = input_filename;
+       location_t saved_location = input_location;
        tree body = EXPR_WFL_NODE (exp);
-       int saved_lineno = lineno;
-       if (body == empty_stmt_node)
+       if (IS_EMPTY_STMT (body))
          break;
+#ifdef USE_MAPPED_LOCATION
+       input_location = EXPR_LOCATION (exp);
+#else
        input_filename = EXPR_WFL_FILENAME (exp);
-       lineno = EXPR_WFL_LINENO (exp);
-       if (EXPR_WFL_EMIT_LINE_NOTE (exp) && lineno > 0
+       input_line = EXPR_WFL_LINENO (exp);
+#endif
+       if (EXPR_WFL_EMIT_LINE_NOTE (exp) && input_line > 0
            && debug_info_level > DINFO_LEVEL_NONE)
-         put_linenumber (lineno, state);
+         put_linenumber (input_line, state);
        generate_bytecode_insns (body, target, state);
-       input_filename = saved_input_filename;
-       lineno = saved_lineno;
+       input_location = saved_location;
       }
       break;
     case INTEGER_CST:
@@ -1460,8 +1522,9 @@ generate_bytecode_insns (tree exp, int target, struct jcf_partial *state)
          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
+       else if (prec == 1 && real_twop (exp))
+         OP1 (OPCODE_fconst_2);
+       /* ??? We could also use iconst_3/ldc followed by i2f/i2d
           for other float/double when the value is a small integer. */
        else
          {
@@ -1539,6 +1602,12 @@ generate_bytecode_insns (tree exp, int target, struct jcf_partial *state)
     case LT_EXPR:
     case GE_EXPR:
     case LE_EXPR:
+    case UNLT_EXPR:
+    case UNLE_EXPR:
+    case UNGT_EXPR:
+    case UNGE_EXPR:
+    case UNEQ_EXPR:
+    case LTGT_EXPR:
       {
        struct jcf_block *then_label = gen_jcf_label (state);
        struct jcf_block *else_label = gen_jcf_label (state);
@@ -1578,8 +1647,8 @@ generate_bytecode_insns (tree exp, int target, struct jcf_partial *state)
     case CASE_EXPR:
       {
        struct jcf_switch_state *sw_state = state->sw_state;
-       struct jcf_relocation *reloc = (struct jcf_relocation *)
-         obstack_alloc (state->chunk_obstack, sizeof (struct jcf_relocation));
+       struct jcf_relocation *reloc
+         obstack_alloc (state->chunk_obstack, sizeof (struct jcf_relocation));
        HOST_WIDE_INT case_value = TREE_INT_CST_LOW (TREE_OPERAND (exp, 0));
        reloc->kind = 0;
        reloc->label = get_jcf_label_here (state);
@@ -1659,8 +1728,8 @@ generate_bytecode_insns (tree exp, int target, struct jcf_partial *state)
            HOST_WIDE_INT i;
            unsigned HOST_WIDE_INT delta;
            /* Copy the chain of relocs into a sorted array. */
-           struct jcf_relocation **relocs = (struct jcf_relocation **)
-             xmalloc (sw_state.num_cases * sizeof (struct jcf_relocation *));
+           struct jcf_relocation **relocs
+             xmalloc (sw_state.num_cases * sizeof (struct jcf_relocation *));
            /* The relocs arrays is a buffer with a gap.
               The assumption is that cases will normally come in "runs". */
            int gap_start = 0;
@@ -1763,7 +1832,7 @@ generate_bytecode_insns (tree exp, int target, struct jcf_partial *state)
     case RETURN_EXPR:
       exp = TREE_OPERAND (exp, 0);
       if (exp == NULL_TREE)
-       exp = empty_stmt_node;
+       exp = build_java_empty_stmt ();
       else if (TREE_CODE (exp) != MODIFY_EXPR) 
        abort ();
       else
@@ -1829,8 +1898,7 @@ generate_bytecode_insns (tree exp, int target, struct jcf_partial *state)
     case EXIT_BLOCK_EXPR:
       {
        struct jcf_block *label = state->labeled_blocks;
-       if (TREE_OPERAND (exp, 1) != NULL) goto notimpl;
-       while (label->u.labeled_block != TREE_OPERAND (exp, 0))
+       while (label->u.labeled_block != EXIT_BLOCK_LABELED_BLOCK (exp))
          label = label->next;
        call_cleanups (label, state);
        emit_goto (label, state);
@@ -1971,8 +2039,7 @@ generate_bytecode_insns (tree exp, int target, struct jcf_partial *state)
        /* If the rhs is a binary expression and the left operand is
           `==' to the lhs then we have an OP= expression.  In this
           case we must do some special processing.  */
-       if (TREE_CODE_CLASS (TREE_CODE (rhs)) == '2'
-           && lhs == TREE_OPERAND (rhs, 0))
+       if (BINARY_CLASS_P (rhs) && lhs == TREE_OPERAND (rhs, 0))
          {
            if (TREE_CODE (lhs) == COMPONENT_REF)
              {
@@ -2018,8 +2085,8 @@ generate_bytecode_insns (tree exp, int target, struct jcf_partial *state)
 
            /* This function correctly handles the case where the LHS
               of a binary expression is NULL_TREE.  */
-           rhs = build (TREE_CODE (rhs), TREE_TYPE (rhs),
-                        NULL_TREE, TREE_OPERAND (rhs, 1));
+           rhs = build2 (TREE_CODE (rhs), TREE_TYPE (rhs),
+                         NULL_TREE, TREE_OPERAND (rhs, 1));
          }
 
        generate_bytecode_insns (rhs, STACK_TARGET, state);
@@ -2079,7 +2146,9 @@ generate_bytecode_insns (tree exp, int target, struct jcf_partial *state)
       jopcode = OPCODE_irem;
       goto binop;
     case LSHIFT_EXPR:   jopcode = OPCODE_ishl;   goto binop;
-    case RSHIFT_EXPR:   jopcode = OPCODE_ishr;   goto binop;
+    case RSHIFT_EXPR:
+      jopcode = TYPE_UNSIGNED (type) ? OPCODE_iushr : 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;
@@ -2092,10 +2161,10 @@ generate_bytecode_insns (tree exp, int target, struct jcf_partial *state)
       tree arg0 = TREE_OPERAND (exp, 0);
       tree arg1 = TREE_OPERAND (exp, 1);
       jopcode += adjust_typed_op (type, 3);
-      if (arg0 == arg1 && TREE_CODE (arg0) == SAVE_EXPR)
+      if (arg0 != NULL_TREE && operand_equal_p (arg0, arg1, 0))
        {
          /* fold may (e.g) convert 2*x to x+x. */
-         generate_bytecode_insns (TREE_OPERAND (arg0, 0), target, state);
+         generate_bytecode_insns (arg0, target, state);
          emit_dup (TYPE_PRECISION (TREE_TYPE (arg0)) > 32 ? 2 : 1, 0, state);
        }
       else
@@ -2148,7 +2217,26 @@ generate_bytecode_insns (tree exp, int target, struct jcf_partial *state)
       }
       break;
     case SAVE_EXPR:
-      generate_bytecode_insns (TREE_OPERAND (exp, 0), STACK_TARGET, state);
+      /* The first time through, the argument of the SAVE_EXPR will be
+        something complex.  Evaluate it, and replace the argument with
+        a VAR_DECL that holds the result.  */
+      arg = TREE_OPERAND (exp, 0);
+      if (TREE_CODE (arg) != VAR_DECL || DECL_NAME (arg))
+       {
+         tree type = TREE_TYPE (exp);
+         tree decl = build_decl (VAR_DECL, NULL_TREE, type);
+         generate_bytecode_insns (arg, STACK_TARGET, state);
+         localvar_alloc (decl, state);
+         TREE_OPERAND (exp, 0) = decl;
+         emit_dup (TYPE_IS_WIDE (type) ? 2 : 1, 0, state);
+         emit_store (decl, state);
+       }
+      else
+       {
+         tree type = TREE_TYPE (exp);
+         emit_load (arg, state);
+         NOTE_PUSH (TYPE_IS_WIDE (type) ? 2 : 1);
+       }
       break;
     case CONVERT_EXPR:
     case NOP_EXPR:
@@ -2174,40 +2262,48 @@ generate_bytecode_insns (tree exp, int target, struct jcf_partial *state)
          }
        else /* Convert numeric types. */
          {
-           int wide_src = TYPE_PRECISION (src_type) > 32;
-           int wide_dst = TYPE_PRECISION (dst_type) > 32;
-           NOTE_POP (1 + wide_src);
-           RESERVE (1);
+           int src_prec = TYPE_PRECISION (src_type);
+           int dst_prec = TYPE_PRECISION (dst_type);
+           int wide_src = src_prec > 32;
+           int wide_dst = dst_prec > 32;
            if (TREE_CODE (dst_type) == REAL_TYPE)
              {
+               NOTE_POP (1 + wide_src);
+               RESERVE (1);
                if (TREE_CODE (src_type) == REAL_TYPE)
                  OP1 (wide_dst ? OPCODE_f2d : OPCODE_d2f);
-               else if (TYPE_PRECISION (src_type) == 64)
+               else if (src_prec == 64)
                  OP1 (OPCODE_l2f + wide_dst);
                else
                  OP1 (OPCODE_i2f + wide_dst);
+               NOTE_PUSH (1 + wide_dst);
              }
-           else /* Convert to integral type. */
+           /* Convert to integral type (but ignore non-widening
+              and non-narrowing integer type conversions).  */
+           else if (TREE_CODE (src_type) == REAL_TYPE
+                    || src_prec != dst_prec)
              {
+               NOTE_POP (1 + wide_src);
+               RESERVE (1);
                if (TREE_CODE (src_type) == REAL_TYPE)
                  OP1 (OPCODE_f2i + wide_dst + 3 * wide_src);
                else if (wide_dst)
                  OP1 (OPCODE_i2l);
                else if (wide_src)
                  OP1 (OPCODE_l2i);
-               if (TYPE_PRECISION (dst_type) < 32)
+               if (dst_prec < 32)
                  {
                    RESERVE (1);
                    /* Already converted to int, if needed. */
-                   if (TYPE_PRECISION (dst_type) <= 8)
+                   if (dst_prec <= 8)
                      OP1 (OPCODE_i2b);
-                   else if (TREE_UNSIGNED (dst_type))
+                   else if (TYPE_UNSIGNED (dst_type))
                      OP1 (OPCODE_i2c);
                    else
                      OP1 (OPCODE_i2s);
                  }
+               NOTE_PUSH (1 + wide_dst);
              }
-           NOTE_PUSH (1 + wide_dst);
          }
       }
       break;
@@ -2354,8 +2450,8 @@ generate_bytecode_insns (tree exp, int target, struct jcf_partial *state)
        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);
          }
       }
@@ -2411,6 +2507,23 @@ generate_bytecode_insns (tree exp, int target, struct jcf_partial *state)
     case JAVA_EXC_OBJ_EXPR:
       NOTE_PUSH (1);  /* Pushed by exception system. */
       break;
+    case MIN_EXPR:
+    case MAX_EXPR:
+      {
+       /* This copes with cases where fold() has created MIN or MAX
+          from a conditional expression.  */
+       enum tree_code code = TREE_CODE (exp) == MIN_EXPR ? LT_EXPR : GT_EXPR;
+       tree op0 = TREE_OPERAND (exp, 0);
+       tree op1 = TREE_OPERAND (exp, 1);
+       tree x;
+       if (TREE_SIDE_EFFECTS (op0) || TREE_SIDE_EFFECTS (op1))
+         abort ();
+       x = build3 (COND_EXPR, TREE_TYPE (exp), 
+                   build2 (code, boolean_type_node, op0, op1), 
+                   op0, op1);    
+       generate_bytecode_insns (x, target, state);
+       break;
+      }                                             
     case NEW_CLASS_EXPR:
       {
        tree class = TREE_TYPE (TREE_TYPE (exp));
@@ -2459,6 +2572,7 @@ generate_bytecode_insns (tree exp, int target, struct jcf_partial *state)
            OP1 (OPCODE_multianewarray);
            OP2 (index);
            OP1 (ndims);
+           NOTE_POP (ndims - 1);
            break;
          }
        else if (f == soft_anewarray_node)
@@ -2549,7 +2663,6 @@ generate_bytecode_insns (tree exp, int target, struct jcf_partial *state)
          }
       }
       /* fall through */
-    notimpl:
     default:
       error("internal error in generate_bytecode_insn - tree code not implemented: %s",
            tree_code_name [(int) TREE_CODE (exp)]);
@@ -2665,8 +2778,7 @@ perform_relocations (struct jcf_partial *state)
       unsigned char *old_ptr = old_buffer + old_size;
       if (new_size != old_size)
        {
-         chunk->data = (unsigned char *)
-           obstack_alloc (state->chunk_obstack, new_size);
+         chunk->data = obstack_alloc (state->chunk_obstack, new_size);
          chunk->size = new_size;
        }
       new_ptr = chunk->data + new_size;
@@ -2693,7 +2805,9 @@ perform_relocations (struct jcf_partial *state)
          int n = (old_ptr - old_buffer) - start;
          new_ptr -= n;
          old_ptr -= n;
-         if (n > 0)
+         /* Don't "copy" bytes in place, this causes valgrind
+            warnings.  */
+         if (n > 0 && new_ptr != old_ptr)
            memcpy (new_ptr, old_ptr, n);
          if (old_ptr == old_buffer)
            break;
@@ -2792,6 +2906,49 @@ release_jcf_state (struct jcf_partial *state)
   obstack_free (state->chunk_obstack, state->first);
 }
 
+/* Get the access flags (modifiers) of a class (TYPE_DECL) to be used in the
+   access_flags field of the class file header.  */
+
+static int
+get_classfile_modifiers (tree class)
+{
+  /* These are the flags which are valid class file modifiers. 
+     See JVMS2 S4.1.  */
+  int valid_toplevel_class_flags = (ACC_PUBLIC | ACC_FINAL | ACC_SUPER | 
+                                   ACC_INTERFACE | ACC_ABSTRACT);
+  int flags = get_access_flags (class);
+
+  /* ACC_SUPER should always be set, except for interfaces.  */
+  if (! (flags & ACC_INTERFACE))
+    flags |= ACC_SUPER;
+   
+  /* A protected member class becomes public at the top level. */
+  if (flags & ACC_PROTECTED)
+    flags |= ACC_PUBLIC;
+  /* Filter out flags that are not valid for a class or interface in the 
+     top-level access_flags field.  */
+  flags &= valid_toplevel_class_flags;
+
+  return flags;
+}
+
+/* Get the access flags (modifiers) for a method to be used in the class 
+   file.  */
+
+static int
+get_method_access_flags (tree decl)
+{
+  int flags = get_access_flags (decl);
+
+  /* Promote "private" inner-class constructors to package-private.  */
+  if (DECL_CONSTRUCTOR_P (decl)
+      && INNER_CLASS_DECL_P (TYPE_NAME (DECL_CONTEXT (decl))))
+    flags &= ~(ACC_PRIVATE);
+
+  return flags;
+}
+
 /* Generate and return a list of chunks containing the class CLAS
    in the .class file representation.  The list can be written to a
    .class file using write_chunks.  Allocate chunks from obstack WORK. */
@@ -2802,16 +2959,15 @@ generate_classfile (tree clas, struct jcf_partial *state)
 {
   struct chunk *cpool_chunk;
   const char *source_file, *s;
-  char *ptr;
+  unsigned char *ptr;
   int i;
-  char *fields_count_ptr;
+  unsigned char *fields_count_ptr;
   int fields_count = 0;
-  char *methods_count_ptr;
+  unsigned char *methods_count_ptr;
   int methods_count = 0;
   tree part;
   int total_supers
-    = clas == object_type_node ? 0
-    : TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (clas));
+    = clas == object_type_node ? 0 : BINFO_N_BASE_BINFOS (TYPE_BINFO (clas));
   
   ptr = append_chunk (NULL, 8, state);
   PUT4 (0xCafeBabe);  /* Magic number */
@@ -2821,16 +2977,14 @@ generate_classfile (tree clas, struct jcf_partial *state)
   append_chunk (NULL, 0, state);
   cpool_chunk = state->chunk;
 
-  /* Next allocate the chunk containing acces_flags through fields_count. */
+  /* Next allocate the chunk containing access_flags through fields_count. */
   if (clas == object_type_node)
     i = 10;
   else
     i = 8 + 2 * total_supers;
   ptr = append_chunk (NULL, i, state);
-  i = get_access_flags (TYPE_NAME (clas));
-  if (! (i & ACC_INTERFACE))
-    i |= ACC_SUPER;
-  PUT2 (i); /* acces_flags */
+  i = get_classfile_modifiers (TYPE_NAME (clas));  
+  PUT2 (i); /* access_flags */
   i = find_class_constant (&state->cpool, clas);  PUT2 (i);  /* this_class */
   if (clas == object_type_node)
     {
@@ -2839,15 +2993,15 @@ generate_classfile (tree clas, struct jcf_partial *state)
     }
   else
     {
-      tree basetypes = TYPE_BINFO_BASETYPES (clas);
-      tree base = BINFO_TYPE (TREE_VEC_ELT (basetypes, 0));
-      int j = find_class_constant (&state->cpool, base);
+      tree binfo = TYPE_BINFO (clas);
+      tree base_binfo = BINFO_BASE_BINFO (binfo, 0);
+      int j = find_class_constant (&state->cpool, BINFO_TYPE (base_binfo));
+      
       PUT2 (j);  /* super_class */
       PUT2 (total_supers - 1);  /* interfaces_count */
-      for (i = 1;  i < total_supers;  i++)
+      for (i = 1; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
        {
-         base = BINFO_TYPE (TREE_VEC_ELT (basetypes, i));
-         j = find_class_constant (&state->cpool, base);
+         j = find_class_constant (&state->cpool, BINFO_TYPE (base_binfo));
          PUT2 (j);
        }
     }
@@ -2918,9 +3072,15 @@ generate_classfile (tree clas, struct jcf_partial *state)
       tree type = TREE_TYPE (part);
       tree save_function = current_function_decl;
       int synthetic_p = 0;
+
+      /* Invisible Miranda methods shouldn't end up in the .class
+        file.  */
+      if (METHOD_INVISIBLE (part))
+       continue;
+
       current_function_decl = part;
       ptr = append_chunk (NULL, 8, state);
-      i = get_access_flags (part);  PUT2 (i);
+      i = get_method_access_flags (part);  PUT2 (i);
       i = find_utf8_constant (&state->cpool, name);  PUT2 (i);
       i = find_utf8_constant (&state->cpool, build_java_signature (type));
       PUT2 (i);
@@ -2949,7 +3109,7 @@ generate_classfile (tree clas, struct jcf_partial *state)
          int code_attributes_count = 0;
          static tree Code_node = NULL_TREE;
          tree t;
-         char *attr_len_ptr;
+         unsigned char *attr_len_ptr;
          struct jcf_handler *handler;
          if (Code_node == NULL_TREE)
            Code_node = get_identifier ("Code");
@@ -2960,6 +3120,7 @@ generate_classfile (tree clas, struct jcf_partial *state)
          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))
            {
@@ -2969,9 +3130,9 @@ generate_classfile (tree clas, struct jcf_partial *state)
              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);
 
@@ -3329,10 +3490,12 @@ make_class_file_name (tree clas)
       if (s == NULL)
        break;
       *s = '\0';
+      /* Try to make directory if it doesn't already exist.  */
       if (stat (r, &sb) == -1
-         /* Try to make it.  */
-         && mkdir (r, 0755) == -1)
-       fatal_io_error ("can't create directory %s", r);
+         && mkdir (r, 0755) == -1
+         /* The directory might have been made by another process.  */
+         && errno != EEXIST)
+       fatal_error ("can't create directory %s: %m", r);
 
       *s = sep;
       /* Skip consecutive separators.  */
@@ -3365,17 +3528,17 @@ write_classfile (tree clas)
       temporary_file_name = concat (class_file_name, ".tmp", NULL);
       stream = fopen (temporary_file_name, "wb");
       if (stream == NULL)
-       fatal_io_error ("can't open %s for writing", temporary_file_name);
+       fatal_error ("can't open %s for writing: %m", temporary_file_name);
 
       jcf_dependency_add_target (class_file_name);
       init_jcf_state (state, work);
       chunks = generate_classfile (clas, state);
       write_chunks (stream, chunks);
       if (fclose (stream))
-       fatal_io_error ("error closing %s", temporary_file_name);
+       fatal_error ("error closing %s: %m", temporary_file_name);
 
       /* If a file named by the string pointed to by `new' exists
-         prior to the call to the `rename' function, the bahaviour
+         prior to the call to the `rename' function, the behavior
          is implementation-defined.  ISO 9899-1990 7.9.4.2.
 
          For example, on Win32 with MSVCRT, it is an error. */
@@ -3385,7 +3548,7 @@ write_classfile (tree clas)
       if (rename (temporary_file_name, class_file_name) == -1)
        {
          remove (temporary_file_name);
-         fatal_io_error ("can't create %s", class_file_name);
+         fatal_error ("can't create %s: %m", class_file_name);
        }
       free (temporary_file_name);
       free (class_file_name);