OSDN Git Service

authorbothner <bothner@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 12 Oct 1998 12:43:53 +0000 (12:43 +0000)
committerbothner <bothner@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 12 Oct 1998 12:43:53 +0000 (12:43 +0000)
Merge from Cygnus internal source tree.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@23025 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/java/Makefile.in
gcc/java/buffer.h
gcc/java/except.c
gcc/java/expr.c
gcc/java/gjavah.c
gcc/java/jcf-parse.c
gcc/java/jcf-write.c
gcc/java/lang.c
gcc/java/parse.h
gcc/java/verify.c

index efe7ef1..d7e009d 100644 (file)
@@ -148,10 +148,12 @@ ALL_CFLAGS = $(INTERNAL_CFLAGS) $(X_CFLAGS) $(T_CFLAGS) $(CFLAGS) $(XCFLAGS)
 # Likewise.
 ALL_CPPFLAGS = $(CPPFLAGS) $(X_CPPFLAGS) $(T_CPPFLAGS)
 
+# CYGNUS LOCAL: SUBDIR_USE_ALLOCA is different from FSF.
 # Even if ALLOCA is set, don't use it if compiling with GCC.
 
 SUBDIR_OBSTACK = `if [ x$(OBSTACK) != x ]; then echo ../$(OBSTACK); else true; fi`
-SUBDIR_USE_ALLOCA = `case "${CC}" in "${OLDCC}") if [ x$(ALLOCA) != x ]; then echo ../$(ALLOCA); else true; fi ;; esac`
+#SUBDIR_USE_ALLOCA = `case "${CC}" in "${OLDCC}") if [ x$(ALLOCA) != x ]; then echo ../$(ALLOCA); else true; fi ;; esac`
+SUBDIR_USE_ALLOCA = `if [ x$(ALLOCA) != x ]; then echo ../$(ALLOCA); else true; fi`
 SUBDIR_MALLOC = `if [ x$(MALLOC) != x ]; then echo ../$(MALLOC); else true; fi`
 
 # How to link with both our special library facilities
@@ -226,19 +228,22 @@ RTL_H = $(srcdir)/../rtl.h $(srcdir)/../rtl.def \
         $(srcdir)/../machmode.h $(srcdir)/../machmode.def
 EXPR_H = $(srcdir)/../expr.h ../insn-codes.h
 
+# CYGNUS LOCAL: we put these files into the build dir.
+PARSE_C = parse.c
+PARSE_SCAN_C = parse-scan.c
 PARSE_H = $(srcdir)/parse.h
-PARSE_C = $(srcdir)/parse.c
-PARSE_SCAN_C = $(srcdir)/parse-scan.c
 
 $(PARSE_C):  $(srcdir)/parse.y $(srcdir)/lex.c $(PARSE_H) $(srcdir)/lex.h
        $(BISON) -t -v $(BISONFLAGS) $(JAVABISONFLAGS) -o $(PARSE_C) \
          $(srcdir)/parse.y
 $(PARSE_SCAN_C):  $(srcdir)/parse-scan.y $(srcdir)/lex.c $(PARSE_H) \
-               $(srcdir)/lex.h
+         $(srcdir)/lex.h
        $(BISON) -t -v $(BISONFLAGS) -o $(PARSE_SCAN_C) $(srcdir)/parse-scan.y
 
 lex.c: keyword.h lex.h
 
+lang.o: $(srcdir)/java-tree.def
+
 keyword.h: keyword.gperf
        gperf -L KR-C -F ', 0' -p -t -j1 -i 1 -g -o -N java_keyword -k1,3,$$ \
        keyword.gperf > keyword.h
@@ -258,8 +263,9 @@ TAGS: force
 mostlyclean:
        rm -f *.o
 
+# CYGNUS LOCAL: Remove these files, as they are in the build dir.
 clean:  mostlyclean
-       rm -f parse.c
+       rm -f parse.c parse-scan.c
 
 force:
 
index aa63840..924f6e0 100644 (file)
@@ -36,6 +36,9 @@ struct buffer
 
 #define NULL_BUFFER { (void*) 0, (void*) 0, (void*) 0 }
 
+#define BUFFER_INIT(BUFP) \
+  ((BUFP)->data = NULL, (BUFP)->ptr = NULL, (BUFP)->limit = NULL)
+
 #define BUFFER_LENGTH(BUFP) ((BUFP)->ptr - (BUFP)->data)
 
 #define BUFFER_RESET(BUFP) ((BUFP)->ptr = (BUFP)->data)
index cbfeb0a..caa2a31 100644 (file)
@@ -161,6 +161,12 @@ method_init_exceptions ()
   whole_range.first_child = NULL;
   whole_range.next_sibling = NULL;
   cache_range_start = 0xFFFFFF;
+  java_set_exception_lang_code ();
+}
+
+void
+java_set_exception_lang_code ()
+{
   set_exception_lang_code (EH_LANG_Java);
   set_exception_version_code (1);
 }
@@ -183,6 +189,32 @@ expand_start_java_handler (range)
   expand_eh_region_start ();
 }
 
+tree
+prepare_eh_table_type (type)
+    tree type;
+{
+  tree exp;
+
+  /* The "type" (metch_info) in a (Java) exception table is one:
+   * a) NULL - meaning match any type in a try-finally.
+   * b) a pointer to a (ccmpiled) class (low-order bit 0).
+   * c) a pointer to the Utf8Const name of the class, plus one
+   * (which yields a value with low-order bit 1). */
+
+  push_obstacks (&permanent_obstack, &permanent_obstack);
+  if (type == NULL_TREE)
+    exp = null_pointer_node;
+  else if (is_compiled_class (type))
+    exp = build_class_ref (type);
+  else
+    exp = fold (build 
+               (PLUS_EXPR, ptr_type_node,
+                build_utf8_ref (build_internal_class_name (type)),
+                size_one_node));
+  pop_obstacks ();
+  return exp;
+}
+
 /* if there are any handlers for this range, isssue end of range,
    and then all handler blocks */
 void
@@ -193,24 +225,8 @@ expand_end_java_handler (range)
   expand_start_all_catch ();
   for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
     {
-      tree type = TREE_PURPOSE (handler);
-      tree exp;
-      /* The "type" (metch_info) in a (Java) exception table is one:
-       * a) NULL - meaning match any type in a try-finally.
-       * b) a pointer to a (ccmpiled) class (low-order bit 0).
-       * c) a pointer to the Utf8Const name of the class, plus one
-       * (which yields a value with low-order bit 1). */
-      push_obstacks (&permanent_obstack, &permanent_obstack);
-      if (type == NULL_TREE)
-       exp = null_pointer_node;
-      else if (is_compiled_class (type))
-       exp = build_class_ref (type);
-      else
-       exp = fold (build (PLUS_EXPR, ptr_type_node,
-                          build_utf8_ref (build_internal_class_name (type)),
-                          size_one_node));
-      pop_obstacks ();
-      start_catch_handler (exp);
+      start_catch_handler (prepare_eh_table_type (TREE_PURPOSE (handler)));
+      /* Push the thrown object on the top of the stack */
       expand_goto (TREE_VALUE (handler));
     }
   expand_end_all_catch ();
index 3b8538c..8322d61 100644 (file)
@@ -460,7 +460,7 @@ java_stack_dup (size, offset)
     }
 }
 
-/* Calls soft_athrow.  Discard the contents of the value stack. */
+/* Calls _Jv_Throw.  Discard the contents of the value stack. */
 
 tree
 build_java_athrow (node)
@@ -526,15 +526,16 @@ decode_newarray_type  (int atype)
     }
 }
 
-/* Build a call to soft_badarrayindex(), the ArrayIndexOfBoundsException
-   exception handler.  */
+/* Build a call to _Jv_ThrowBadArrayIndex(), the
+   ArrayIndexOfBoundsException exception handler.  */
 
 static tree
-build_java_throw_out_of_bounds_exception ()
+build_java_throw_out_of_bounds_exception (index)
+    tree index;
 {
   tree node = build (CALL_EXPR, int_type_node,
                     build_address_of (soft_badarrayindex_node), 
-                    NULL_TREE, NULL_TREE );
+                    build_tree_list (NULL_TREE, index), NULL_TREE);
   TREE_SIDE_EFFECTS (node) = 1;        /* Allows expansion within ANDIF */
   return (node);
 }
@@ -629,7 +630,7 @@ build_java_arrayaccess (array, type, index)
       if (! integer_zerop (test))
        {
          throw = build (TRUTH_ANDIF_EXPR, int_type_node, test,
-                        build_java_throw_out_of_bounds_exception ());
+                        build_java_throw_out_of_bounds_exception (index));
          /* allows expansion within COMPOUND */
          TREE_SIDE_EFFECTS( throw ) = 1;
        }
@@ -677,7 +678,7 @@ build_java_check_indexed_type (array_node, indexed_type)
     return indexed_type;
 }
 
-/* newarray triggers a call to soft_newarray. This function should be called
+/* newarray triggers a call to _Jv_NewArray. This function should be called
    with an integer code (the type of array to create) and get from the stack
    the size of the dimmension.  */
 
@@ -706,7 +707,7 @@ build_anewarray (class_type, length)
     tree class_type;
     tree length;
 {
-  tree type = build_java_array_type (promote_type (class_type),
+  tree type = build_java_array_type (class_type,
                                     TREE_CODE (length) == INTEGER_CST
                                     ? TREE_INT_CST_LOW (length)
                                     : -1);
@@ -719,9 +720,9 @@ build_anewarray (class_type, length)
                NULL_TREE);
 }
 
-/* Generates a call to multianewarray. multianewarray expects a class pointer,
-   a number of dimensions and the matching number of dimensions. The argument
-   list is NULL terminated.  */
+/* Generates a call to _Jv_NewMultiArray. multianewarray expects a
+   class pointer, a number of dimensions and the matching number of
+   dimensions. The argument list is NULL terminated.  */
 
 void
 expand_java_multianewarray (class_type, ndim)
@@ -829,8 +830,8 @@ expand_java_array_length ()
   push_value (build_java_arraynull_check (array, length, int_type_node));
 }
 
-/* Emit code for the call to soft_monitor{enter,exit}. CALL can be either
-   soft_monitorenter_node or soft_monitorexit_node.  */
+/* Emit code for the call to _Jv_Monitor{Enter,Exit}. CALL can be
+   either soft_monitorenter_node or soft_monitorexit_node.  */
 
 tree
 build_java_monitor (call, object)
@@ -1147,6 +1148,18 @@ lookup_label (pc)
     }
 }
 
+/* Generate a unique name for the purpose of loops and switches
+   labels, and try-catch-finally blocks label or temporary variables.  */
+
+tree
+generate_name ()
+{
+  static int l_number = 0;
+  char buff [20];
+  sprintf (buff, "$L%d", l_number++);
+  return get_identifier (buff);
+}
+
 tree
 create_label_decl (name)
      tree name;
@@ -1175,7 +1188,6 @@ note_label (current_pc, target_pc)
 /* Emit code to jump to TARGET_PC if VALUE1 CONDITION VALUE2,
    where CONDITION is one of one the compare operators. */
 
-
 void
 expand_compare (condition, value1, value2, target_pc)
      enum tree_code condition;
@@ -1279,7 +1291,14 @@ pop_arguments (arg_types)
   if (TREE_CODE (arg_types) == TREE_LIST)
     {
       tree tail = pop_arguments (TREE_CHAIN (arg_types));
-      return tree_cons (NULL_TREE, pop_value (TREE_VALUE (arg_types)), tail);
+      tree type = TREE_VALUE (arg_types);
+      tree arg = pop_value (type);
+#ifdef PROMOTE_PROTOTYPES
+      if (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)
+         && INTEGRAL_TYPE_P (type))
+       arg = convert (integer_type_node, arg);
+#endif
+      return tree_cons (NULL_TREE, arg, tail);
     }
   abort ();
 }
@@ -1490,17 +1509,6 @@ expand_invoke (opcode, method_ref_index, nargs)
   arg_list = pop_arguments (TYPE_ARG_TYPES (method_type));
   flush_quick_stack ();
 
-  if (opcode == OPCODE_invokestatic || opcode == OPCODE_invokespecial
-      && ! inherits_from_p (current_class, self_type))
-    { /* FIXME probably not needed for invokespecial if done by NEW. */
-      /* Ensure self_type is initialized. */ 
-      func = build (CALL_EXPR, void_type_node, soft_initclass_node,
-                   build_tree_list (NULL_TREE,
-                                    build_class_ref (self_type)),
-                   NULL_TREE);
-      expand_expr_stmt (func);
-    }
-
   func = NULL_TREE;
   if (opcode == OPCODE_invokestatic || opcode == OPCODE_invokespecial
       || (opcode == OPCODE_invokevirtual
@@ -1515,9 +1523,9 @@ expand_invoke (opcode, method_ref_index, nargs)
        func = build_invokevirtual (dtable, method);
       else
        {
-         /* We expand invokeinterface here. soft_lookupinterfacemethod () will
-            ensure that the selected method exists, is public and not abstract
-            nor static.  */
+         /* We expand invokeinterface here.
+            _Jv_LookupInterfaceMethod() will ensure that the selected
+            method exists, is public and not abstract nor static.  */
            
          tree lookup_arg;
 
@@ -1543,12 +1551,6 @@ expand_invoke (opcode, method_ref_index, nargs)
   call = build (CALL_EXPR, TREE_TYPE (method_type), func, arg_list, NULL_TREE);
   TREE_SIDE_EFFECTS (call) = 1;
 
-  if (opcode == OPCODE_invokestatic || opcode == OPCODE_invokespecial)
-    { /* FIXME probably not needed for invokespecial if done by NEW. */
-      /* Ensure self_type is initialized. */ 
-      call = build_class_init (self_type, call);
-    }
-
   if (TREE_CODE (TREE_TYPE (method_type)) == VOID_TYPE)
     expand_expr_stmt (call);
   else
@@ -1600,7 +1602,7 @@ expand_java_field_op (is_static, is_putting, field_ref_index)
   if (is_error)
     {
       if (! is_putting)
-       push_value (convert (promote_type (field_type), integer_zero_node));
+       push_value (convert (field_type, integer_zero_node));
       flush_quick_stack ();
       return;
     }
@@ -1610,7 +1612,7 @@ expand_java_field_op (is_static, is_putting, field_ref_index)
      this is also needed to avoid circularities in the implementation
      of these fields in libjava. */
   if (field_name == TYPE_identifier_node && ! is_putting
-      && field_type == class_type_node
+      && field_type == class_ptr_type
       && strncmp (self_name, "java.lang.", 10) == 0)
     {
       char *class_name = self_name+10;
@@ -1693,6 +1695,8 @@ java_lang_expand_expr (exp, target, tmode, modifier)
   tree type = TREE_TYPE (exp);
   register enum machine_mode mode = TYPE_MODE (type);
   int unsignedp = TREE_UNSIGNED (type);
+  tree node, current;
+  int has_finally_p;
 
   switch (TREE_CODE (exp))
     {
@@ -1719,6 +1723,61 @@ java_lang_expand_expr (exp, target, tmode, modifier)
        }
       break;
 
+    case SWITCH_EXPR:
+      java_expand_switch (exp);
+      return const0_rtx;
+
+    case TRY_EXPR:
+      /* We expand a try[-catch][-finally] block */
+
+      /* Expand the try block */
+      expand_eh_region_start ();
+      expand_expr_stmt (TREE_OPERAND (exp, 0));
+      expand_start_all_catch ();
+      has_finally_p = (TREE_OPERAND (exp, 2) ? 1 : 0);
+
+      /* Expand all catch clauses (EH handlers) */
+      for (current = TREE_OPERAND (exp, 1); current; 
+          current = TREE_CHAIN (current))
+       {
+         extern rtx return_label;
+         tree type;
+         /* If we have a finally, the last exception handler is the
+            one that is supposed to catch everything. */
+         if (has_finally_p && !TREE_CHAIN (current))
+           type = NULL_TREE;
+         else
+           {
+             tree catch = java_get_catch_block (current, has_finally_p);
+             tree decl = BLOCK_EXPR_DECLS (catch);
+             type = TREE_TYPE (TREE_TYPE (decl));
+           }
+         start_catch_handler (prepare_eh_table_type (type));
+         expand_expr_stmt (TREE_OPERAND (current, 0));
+
+         /* Need to expand a goto to the end of the function here,
+            but not for the catch everything handler. */
+         if (type)
+           {
+             if (return_label)
+               emit_jump (return_label);
+             else
+               fatal ("No return_label for this function - "
+                      "java_lang_expand_expr");
+           }
+         end_catch_handler ();
+       }
+
+      /* Expand the finally block, if any */
+      if (has_finally_p)
+       {
+         tree finally = TREE_OPERAND (exp, 2);
+         emit_label (label_rtx (FINALLY_EXPR_LABEL (finally)));
+         expand_expr_stmt (FINALLY_EXPR_BLOCK (finally));
+       }
+      expand_end_all_catch ();
+      break;
+
     default:
       fatal ("Can't expand '%s' tree - java_lang_expand_expr",
             tree_code_name [TREE_CODE (exp)]);
@@ -1984,6 +2043,15 @@ process_jvm_instruction (PC, byte_ops, length)
 { 
   char *opname; /* Temporary ??? */
   int oldpc = PC; /* PC at instruction start. */
+
+  /* If the instruction is at the beginning of a exception handler,
+     replace the top of the stack with the thrown object reference */
+  if (instruction_bits [PC] & BCODE_EXCEPTION_TARGET)
+    {
+      pop_value (ptr_type_node);
+      push_value (soft_exceptioninfo_call_node);
+    }
+
   switch (byte_ops[PC++])
     {
 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
index fd39df6..b6229cc 100644 (file)
@@ -84,11 +84,21 @@ static JCF_u2 last_access;
 
 #define ACC_VISIBILITY (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED)
 
-int seen_fields = 0;
+/* We keep a linked list of all method names we have seen.  This lets
+   us determine if a method name and a field name are in conflict.  */
+struct method_name
+{
+  unsigned char *name;
+  int length;
+  struct method_name *next;
+};
+
+/* List of method names we've seen.  */
+static struct method_name *method_name_list;
 
 static void print_field_info PROTO ((FILE *, JCF*, int, int, JCF_u2));
 static void print_method_info PROTO ((FILE *, JCF*, int, int, JCF_u2));
-static void print_c_decl PROTO ((FILE*, JCF*, int, int, JCF_u2, int));
+static void print_c_decl PROTO ((FILE*, JCF*, int, int, JCF_u2, int, char *));
 
 JCF_u2 current_field_name;
 JCF_u2 current_field_value;
@@ -99,9 +109,15 @@ JCF_u2 current_field_flags;
 ( current_field_name = (NAME), current_field_signature = (SIGNATURE), \
   current_field_flags = (ACCESS_FLAGS), current_field_value = 0)
 
+/* We pass over fields twice.  The first time we just note the start
+   of the methods.  Then we go back and parse the fields for real.
+   This is ugly.  */
+static int field_pass;
+
 #define HANDLE_END_FIELD() \
-  print_field_info (out, jcf, current_field_name, current_field_signature, \
-                   current_field_flags);
+  if (field_pass) print_field_info (out, jcf, current_field_name, \
+                                   current_field_signature, \
+                                   current_field_flags);
 
 #define HANDLE_CONSTANTVALUE(VALUEINDEX) current_field_value = (VALUEINDEX)
 
@@ -242,11 +258,29 @@ generate_access (stream, flags)
     }
 }
 
+/* See if NAME is already the name of a method.  */
+static int
+name_is_method_p (name, length)
+     unsigned char *name;
+     int length;
+{
+  struct method_name *p;
+
+  for (p = method_name_list; p != NULL; p = p->next)
+    {
+      if (p->length == length && ! memcmp (p->name, name, length))
+       return 1;
+    }
+  return 0;
+}
+
 static void
 DEFUN(print_field_info, (stream, jcf, name_index, sig_index, flags),
       FILE *stream AND JCF* jcf
       AND int name_index AND int sig_index AND JCF_u2 flags)
 {
+  char *override = NULL;
+
   if (flags & ACC_FINAL)
     {
       if (current_field_value > 0)
@@ -305,12 +339,42 @@ DEFUN(print_field_info, (stream, jcf, name_index, sig_index, flags),
 
   generate_access (stream, flags);
   fputs ("  ", out);
-  if (flags & ACC_STATIC)
+  if ((flags & ACC_STATIC))
     fputs ("static ", out);
-  print_c_decl (out, jcf, name_index, sig_index, flags, 0);
+
+  if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
+    {
+      fprintf (stream, "<not a UTF8 constant>");
+      found_error = 1;
+    }
+  else
+    {
+      unsigned char *name = JPOOL_UTF_DATA (jcf, name_index);
+      int length = JPOOL_UTF_LENGTH (jcf, name_index);
+
+      if (name_is_method_p (name, length))
+       {
+         /* This field name matches a method.  So override the name
+            with a dummy name.  This is yucky, but it isn't clear
+            what else to do.  FIXME: if the field is static, then
+            we'll be in real trouble.  */
+         if ((flags & ACC_STATIC))
+           {
+             fprintf (stderr, "static field has same name as method\n");
+             found_error = 1;
+           }
+
+         override = (char *) malloc (length + 3);
+         memcpy (override, name, length);
+         strcpy (override + length, "__");
+       }
+    }
+
+  print_c_decl (out, jcf, name_index, sig_index, flags, 0, override);
   fputs (";\n", out);
-  if (! (flags & ACC_STATIC))
-    seen_fields++;
+
+  if (override)
+    free (override);
 }
 
 static void
@@ -320,6 +384,7 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
 {
   unsigned char *str;
   int length, is_init = 0;
+  char *override = NULL;
 
   if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
     fprintf (stream, "<not a UTF8 constant>");
@@ -334,13 +399,33 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
       else  
        return;
     }
+  else
+    {
+      struct method_name *nn;
+
+      nn = (struct method_name *) malloc (sizeof (struct method_name));
+      nn->name = (char *) malloc (length);
+      memcpy (nn->name, str, length);
+      nn->length = length;
+      nn->next = method_name_list;
+      method_name_list = nn;
+    }
 
   /* We can't generate a method whose name is a C++ reserved word.
      For now the only problem has been `delete'; add more here as
-     required.  FIXME: we need a better solution than just ignoring
-     the method.  */
+     required.  We can't just ignore the function, because that will
+     cause incorrect code to be generated if the function is virtual
+     (not only for calls to this function for for other functions
+     after it in the vtbl).  So we give it a dummy name instead.  */
   if (! utf8_cmp (str, length, "delete"))
-    return;
+    {
+      /* If the method is static, we can safely skip it.  If we don't
+        skip it then we'll have problems since the mangling will be
+        wrong.  FIXME.  */
+      if ((flags & ACC_STATIC))
+       return;
+      override = "__dummy_delete";
+    }
 
   generate_access (stream, flags);
 
@@ -353,7 +438,7 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
       if (! is_init)
        fputs ("virtual ", out);
     }
-  print_c_decl (out, jcf, name_index, sig_index, flags, is_init);
+  print_c_decl (out, jcf, name_index, sig_index, flags, is_init, override);
 
   /* FIXME: it would be nice to decompile small methods here.  That
      would allow for inlining.  */
@@ -361,154 +446,185 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
   fprintf(out, ";\n");
 }
 
+/* Print one piece of a signature.  Returns pointer to next parseable
+   character on success, NULL on error.  */
+static unsigned char *
+decode_signature_piece (stream, signature, limit, need_space)
+     FILE *stream;
+     unsigned char *signature, *limit;
+     int *need_space;
+{
+  char *ctype;
+
+  switch (signature[0])
+    {
+    case '[':
+      for (signature++; (signature < limit
+                        && *signature >= '0'
+                        && *signature <= '9'); signature++)
+       ;
+      switch (*signature)
+       {
+       case 'B': ctype = "jbyteArray";  goto printit;
+       case 'C': ctype = "jcharArray";  goto printit;
+       case 'D': ctype = "jdoubleArray";  goto printit;
+       case 'F': ctype = "jfloatArray";  goto printit;
+       case 'I': ctype = "jintArray";  goto printit;
+       case 'S': ctype = "jshortArray";  goto printit;
+       case 'J': ctype = "jlongArray";  goto printit;
+       case 'Z': ctype = "jbooleanArray";  goto printit;
+       case '[': ctype = "jobjectArray"; goto printit;
+       case 'L':
+         /* We have to generate a reference to JArray here,
+            so that our output matches what the compiler
+            does.  */
+         ++signature;
+         fputs ("JArray<", stream);
+         while (signature < limit && *signature != ';')
+           {
+             int ch = UTF8_GET (signature, limit);
+             if (ch == '/')
+               fputs ("::", stream);
+             else
+               jcf_print_char (stream, ch);
+           }
+         fputs (" *> *", stream);
+         *need_space = 0;
+         ++signature;
+         break;
+       default:
+         /* Unparseable signature.  */
+         return NULL;
+       }
+      break;
+
+    case '(':
+    case ')':
+      /* This shouldn't happen.  */
+      return NULL;
+
+    case 'B': ctype = "jbyte";  goto printit;
+    case 'C': ctype = "jchar";  goto printit;
+    case 'D': ctype = "jdouble";  goto printit;
+    case 'F': ctype = "jfloat";  goto printit;
+    case 'I': ctype = "jint";  goto printit;
+    case 'J': ctype = "jlong";  goto printit;
+    case 'S': ctype = "jshort";  goto printit;
+    case 'Z': ctype = "jboolean";  goto printit;
+    case 'V': ctype = "void";  goto printit;
+    case 'L':
+      ++signature;
+      while (*signature && *signature != ';')
+       {
+         int ch = UTF8_GET (signature, limit);
+         if (ch == '/')
+           fputs ("::", stream);
+         else
+           jcf_print_char (stream, ch);
+       }
+      fputs (" *", stream);
+      if (*signature == ';')
+       signature++;
+      *need_space = 0;
+      break;
+    default:
+      *need_space = 1;
+      jcf_print_char (stream, *signature++);
+      break;
+    printit:
+      signature++;
+      *need_space = 1;
+      fputs (ctype, stream);
+      break;
+    }
+
+  return signature;
+}
+
 static void
-DEFUN(print_c_decl, (stream, jcf, name_index, signature_index, flags, is_init),
+DEFUN(print_c_decl, (stream, jcf, name_index, signature_index, flags, is_init,
+                    name_override),
       FILE* stream AND JCF* jcf
       AND int name_index AND int signature_index AND JCF_u2 flags
-      AND int is_init)
+      AND int is_init AND char *name_override)
 {
   if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
-    fprintf (stream, "<not a UTF8 constant>");
+    {
+      fprintf (stream, "<not a UTF8 constant>");
+      found_error = 1;
+    }
   else
     {
       int length = JPOOL_UTF_LENGTH (jcf, signature_index);
       unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
       register  unsigned char *str = str0;
       unsigned char *limit = str + length;
-      int j;
-      char *ctype;
       int need_space = 0;
       int is_method = str[0] == '(';
+      unsigned char *next;
 
-      if (is_method)
+      /* If printing a method, skip to the return signature and print
+        that first.  However, there is no return value if this is a
+        constructor.  */
+      if (is_method && ! is_init)
        {
-         /* Skip to the return signature, and print that first.
-            However, don't do this is we are printing a construtcor.
-            */
-         if (is_init)
+         while (str < limit)
            {
-             str = str0 + 1;
-             /* FIXME: Most programmers love Celtic knots because
-                they see their own code in the interconnected loops.
-                That is, this is spaghetti.  */
-             goto have_constructor;
-           }
-         else
-           {
-             while (str < limit)
-               {
-                 int ch = *str++;
-                 if (ch == ')')
-                   break;
-               }
+             int ch = *str++;
+             if (ch == ')')
+               break;
            }
        }
 
-    again:
-      while (str < limit)
+      /* If printing a field or an ordinary method, then print the
+        "return value" now.  */
+      if (! is_method || ! is_init)
        {
-         switch (str[0])
+         next = decode_signature_piece (stream, str, limit, &need_space);
+         if (! next)
            {
-           case '[':
-             for (str++; str < limit && *str >= '0' && *str <= '9'; str++)
-               ;
-             switch (*str)
-               {
-               case 'B': ctype = "jbyteArray";  goto printit;
-               case 'C': ctype = "jcharArray";  goto printit;
-               case 'D': ctype = "jdoubleArray";  goto printit;
-               case 'F': ctype = "jfloatArray";  goto printit;
-               case 'I': ctype = "jintArray";  goto printit;
-               case 'S': ctype = "jshortArray";  goto printit;
-               case 'J': ctype = "jlongArray";  goto printit;
-               case 'Z': ctype = "jbooleanArray";  goto printit;
-               case '[': ctype = "jobjectArray"; goto printit;
-               case 'L':
-                 /* We have to generate a reference to JArray here,
-                    so that our output matches what the compiler
-                    does.  */
-                 ++str;
-                 fputs ("JArray<", out);
-                 while (str < limit && *str != ';')
-                   {
-                     int ch = UTF8_GET (str, limit);
-                     if (ch == '/')
-                       fputs ("::", stream);
-                     else
-                       jcf_print_char (stream, ch);
-                   }
-                 fputs (" *> *", out);
-                 need_space = 0;
-                 ++str;
-                 break;
-               default:
-                 fprintf (stderr, "unparseable signature `%s'\n", str0);
-                 found_error = 1;
-                 ctype = "???"; goto printit;
-               }
-             break;
-           case '(':
-             fputc (*str++, stream);
-             continue;
-           case ')':
-             fputc (*str++, stream);
-             /* the return signature was printed in the first pass. */
+             fprintf (stderr, "unparseable signature: `%s'\n", str0);
+             found_error = 1;
              return;
-           case 'B': ctype = "jbyte";  goto printit;
-           case 'C': ctype = "jchar";  goto printit;
-           case 'D': ctype = "jdouble";  goto printit;
-           case 'F': ctype = "jfloat";  goto printit;
-           case 'I': ctype = "jint";  goto printit;
-           case 'J': ctype = "jlong";  goto printit;
-           case 'S': ctype = "jshort";  goto printit;
-           case 'Z': ctype = "jboolean";  goto printit;
-           case 'V': ctype = "void";  goto printit;
-           case 'L':
-             ++str;
-             while (*str && *str != ';')
-               {
-                 int ch = UTF8_GET (str, limit);
-                 if (ch == '/')
-                   fputs ("::", stream);
-                 else
-                   jcf_print_char (stream, ch);
-               }
-             fputs (" *", stream);
-             if (*str == ';')
-               str++;
-             need_space = 0;
-             break;
-           default:
-             need_space = 1;
-             jcf_print_char (stream, *str++);
-             break;
-           printit:
-             str++;
-             need_space = 1;
-             fputs (ctype, stream);
-             break;
            }
-
-         if (is_method && str < limit && *str != ')')
-           fputs (", ", stream);
        }
-    have_constructor:
-      if (name_index)
+
+      /* Now print the name of the thing.  */
+      if (need_space)
+       fputs (" ", stream);
+      if (name_override)
+       fputs (name_override, stream);
+      else if (name_index)
        {
-         if (need_space)
-           fprintf (stream, " ");
          /* Declare constructors specially.  */
          if (is_init)
            print_base_classname (stream, jcf, jcf->this_class);
          else
            print_name (stream, jcf, name_index);
        }
+
       if (is_method)
        {
+         /* Have a method or a constructor.  Print signature pieces
+            until done.  */
          fputs (" (", stream);
-         /* Go to beginning, skipping '('. */
          str = str0 + 1;
-         goto again; /* To handle argument signatures. */
+         while (str < limit && *str != ')')
+           {
+             next = decode_signature_piece (stream, str, limit, &need_space);
+             if (! next)
+               {
+                 fprintf (stderr, "unparseable signature: `%s'\n", str0);
+                 found_error = 1;
+                 return;
+               }
+
+             if (next < limit && *next != ')')
+               fputs (", ", stream);
+             str = next;
+           }
+
+         fputs (")", stream);
        }
     }
 }
@@ -613,6 +729,7 @@ DEFUN(process_file, (jcf, out),
       JCF *jcf AND FILE *out)
 {
   int code, i;
+  uint32 field_start, method_end;
 
   current_jcf = main_jcf = jcf;
 
@@ -700,8 +817,22 @@ DEFUN(process_file, (jcf, out),
      as we see them.  We have to list the methods in the same order
      that they appear in the class file, so that the Java and C++
      vtables have the same layout.  */
+  /* We want to parse the methods first.  But we need to find where
+     they start.  So first we skip the fields, then parse the
+     methods.  Then we parse the fields and skip the methods.  FIXME:
+     this is ugly.  */
+  field_pass = 0;
+  field_start = JCF_TELL (jcf);
   jcf_parse_fields (jcf);
+
   jcf_parse_methods (jcf);
+  method_end = JCF_TELL (jcf);
+
+  field_pass = 1;
+  JCF_SEEK (jcf, field_start);
+  jcf_parse_fields (jcf);
+  JCF_SEEK (jcf, method_end);
+
   jcf_parse_final_attributes (jcf);
 
   /* Generate friend decl if we still must.  */
index cdcbced..e6b8ba1 100644 (file)
@@ -408,7 +408,7 @@ get_class_constant (JCF *jcf , int i)
       char *name = JPOOL_UTF_DATA (jcf, name_index);
       int nlength = JPOOL_UTF_LENGTH (jcf, name_index);
       if (name[0] == '[')  /* Handle array "classes". */
-         type = parse_signature_string (name, nlength);
+         type = TREE_TYPE (parse_signature_string (name, nlength));
       else
         { 
           tree cname = unmangle_classname (name, nlength);
index af66301..deda8c1 100644 (file)
@@ -35,19 +35,16 @@ The Free Software Foundation is independent of Sun Microsystems, Inc.  */
 
 extern struct obstack temporary_obstack;
 
-/* The buffer allocated for bytecode for the current method. */
-
-struct buffer bytecode = NULL_BUFFER;
-
 /* Make sure bytecode.data is big enough for at least N more bytes. */
 
 #define RESERVE(N) \
-  do { if (bytecode.ptr + (N) > bytecode.limit) buffer_grow (&bytecode, N); } while (0)
+  do { if (state->bytecode.ptr + (N) > state->bytecode.limit) \
+    buffer_grow (&state->bytecode, N); } while (0)
 
 /* Add a 1-byte instruction/operand I to bytecode.data,
    assuming space has already been RESERVE'd. */
 
-#define OP1(I) (*bytecode.ptr++ = (I))
+#define OP1(I) (*state->bytecode.ptr++ = (I))
 
 /* Like OP1, but I is a 2-byte big endian integer. */
 
@@ -73,12 +70,14 @@ CPool *code_cpool;
 /* Macro to call each time we push I words on the JVM stack. */
 
 #define NOTE_PUSH(I) \
-  do { code_SP += (I); if (code_SP > code_SP_max) code_SP_max = code_SP; } while (0)
+  do { state->code_SP += (I); \
+    if (state->code_SP > state->code_SP_max) \
+      state->code_SP_max = state->code_SP; } while (0)
 
 /* Macro to call each time we pop I words from the JVM stack. */
 
 #define NOTE_POP(I) \
-  do { code_SP -= (I); if (code_SP < 0) abort(); } while (0)
+  do { state->code_SP -= (I); if (state->code_SP < 0) abort(); } while (0)
 
 /* A chunk or segment of a .class file. */
 
@@ -94,6 +93,103 @@ struct chunk
   int size;
 };
 
+/* Each "block" represents a label plus the bytecode instructions following.
+   There may be branches out of the block, but no incoming jumps, except
+   to the beginning of the block. */
+
+struct jcf_block
+{
+  /* For blocks that that are defined, the next block (in pc order).
+     For blocks that are the not-yet-defined end label of a LABELED_BLOCK_EXPR,
+     this is the next (outer) such end label, in a stack heaed by
+     labeled_blocks in jcf_partial. */
+  struct jcf_block *next;
+
+  /* Until perform_relocations is finished, this is the maximum possible
+     value of the bytecode offset at the begnning of this block.
+     After perform_relocations, it is the actual offset (pc). */
+  int pc;
+
+  int linenumber;
+
+  struct chunk *chunk;
+
+  union {
+    /* Set of relocations (in reverse offset order) for this block. */
+    struct jcf_relocation *relocations;
+
+    /* If this block is that of the not-yet-defined end label of
+       a LABELED_BLOCK_EXPR, where LABELED_BLOCK is that LABELED_BLOCK_EXPR. */
+    tree labeled_block;
+  } u;
+};
+
+struct jcf_relocation
+{
+  /* Next relocation for the current jcf_block. */
+  struct jcf_relocation *next;
+
+  /* The (byte) offset within the current block that needs to be relocated. */
+  int offset;
+
+  /* 0 if offset is a 4-byte relative offset.
+     -1 if offset is a 2-byte relative offset.
+     < 0 if offset is the address of an instruction with a 2-byte offset
+     that does not have a corresponding 4-byte offset version, in which
+     case the absolute value of kind is the inverted opcode.
+     > 0 if offset is the address of an instruction (such as jsr) with a
+     2-byte offset that does have a corresponding 4-byte offset version,
+     in which case kind is the opcode of the 4-byte version (such as jsr_w). */
+  int kind;
+
+  /* The label the relocation wants to actually transfer to. */
+  struct jcf_block *label;
+};
+
+/* This structure is used to contain the various pieces that will
+   become a .class file. */
+
+struct jcf_partial
+{
+  struct chunk *first;
+  struct chunk *chunk;
+  struct obstack *chunk_obstack;
+  tree current_method;
+
+  /* List of basic blocks for the current method. */
+  struct jcf_block *blocks;
+  struct jcf_block *last_block;
+
+  struct localvar_info *first_lvar;
+  struct localvar_info *last_lvar;
+  int lvar_count;
+
+  CPool cpool;
+
+  int linenumber_count;
+
+  /* Until perform_relocations, this is a upper bound on the number
+     of bytes (so far) in the instructions for the current method. */
+  int code_length;
+
+  /* Stack of undefined ending labels for LABELED_BLOCK_EXPR. */
+  struct jcf_block *labeled_blocks;
+  
+  /* The current stack size (stack pointer) in the current method. */
+  int code_SP;
+
+  /* The largest extent of stack size (stack pointer) in the current method. */
+  int code_SP_max;
+
+  /* Contains a mapping from local var slot number to localvar_info. */
+  struct buffer localvars;
+
+  /* The buffer allocated for bytecode for the current jcf_block. */
+  struct buffer bytecode;
+};
+
+static void generate_bytecode_insns PROTO ((tree, int, struct jcf_partial *));
+
 /* Utility macros for appending (big-endian) data to a buffer.
    We assume a local variable 'ptr' points into where we want to
    write next, and we assume enoygh space has been allocated. */
@@ -104,162 +200,228 @@ struct chunk
 #define PUTN(P, N)  (bcopy(P, ptr, N), ptr += (N))
 
 \f
-/* A buffer for storing line number entries for the current method. */
-struct buffer linenumbers = NULL_BUFFER;
+/* 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 *
+alloc_chunk (last, data, size, work)
+     struct chunk *last;
+     unsigned char *data;
+     int size;
+     struct obstack *work;
+{
+  struct chunk *chunk = (struct chunk *)
+    obstack_alloc (work, sizeof(struct chunk));
+
+  if (data == NULL && size > 0)
+    data = obstack_alloc (work, size);
+
+  chunk->next = NULL;
+  chunk->data = data;
+  chunk->size = size;
+  if (last != NULL)
+    last->next = chunk;
+  return chunk;
+}
+
+unsigned char *
+append_chunk (data, size, state)
+     unsigned char *data;
+     int size;
+     struct jcf_partial *state;
+{
+  state->chunk = alloc_chunk (state->chunk, data, size, state->chunk_obstack);
+  if (state->first == NULL)
+    state->first = state->chunk;
+  return state->chunk->data;
+}
+
+void
+append_chunk_copy (data, size, state)
+     unsigned char *data;
+     int size;
+     struct jcf_partial *state;
+{
+  unsigned char *ptr = append_chunk (NULL, size, state);
+  bcopy (data, ptr, size);
+}
+\f
+struct jcf_block *
+gen_jcf_label (state)
+     struct jcf_partial *state;
+{
+  struct jcf_block *block = (struct jcf_block *)
+    obstack_alloc (state->chunk_obstack, sizeof (struct jcf_block));
+  block->next =        NULL;
+  block->linenumber = -1;
+  block->pc = -1;
+  return block;
+}
+
+void
+finish_jcf_block (state)
+     struct jcf_partial *state;
+{
+  struct jcf_block *block = state->last_block;
+  struct jcf_relocation *reloc;
+  int pc = state->code_length;
+  append_chunk_copy (state->bytecode.data, BUFFER_LENGTH (&state->bytecode),
+                    state);
+  BUFFER_RESET (&state->bytecode);
+  block->chunk = state->chunk;
+
+  /* Calculate code_length to the maximum value it can have. */
+  pc += block->chunk->size;
+  for (reloc = block->u.relocations;  reloc != NULL;  reloc = reloc->next)
+    {
+      int kind = reloc->kind;
+      if (kind > 0)
+       pc += 2; /* 2-byte offset may grow to 4-byte offset */
+      else if (kind < -1)
+       pc += 5; /* May need to add a goto_w. */
+    }
+  state->code_length = pc;
+}
+
+void
+define_jcf_label (label, state)
+     struct jcf_block *label;
+     struct jcf_partial *state;
+{
+  if (state->last_block != NULL)
+    finish_jcf_block (state);
+  label->pc = state->code_length;
+  if (state->blocks == NULL)
+    state->blocks = label;
+  else
+    state->last_block->next = label;
+  state->last_block = label;
+  label->next = NULL;
+  label->u.relocations = NULL;
+}
+
+struct jcf_block *
+get_jcf_label_here (state)
+     struct jcf_partial *state;
+{
+  if (state->last_block != NULL && BUFFER_LENGTH (&state->bytecode) == 0)
+    return state->last_block;
+  else
+    {
+      struct jcf_block *label = gen_jcf_label (state);
+      define_jcf_label (label, state);
+      return label;
+    }
+}
 
-/* Append a line number entry for the given PC and LINE into
-   linenumbers.data.  This will later before a LineNumberTable attribute. */
+/* Note a line number entry for the current PC and given LINE. */
 
 void
-put_linenumber (pc, line)
-     int pc, line;
+put_linenumber (line, state)
+     int line;
+     struct jcf_partial *state;
 {
-  register unsigned char *ptr;
-  if (linenumbers.ptr == linenumbers.limit)
-    buffer_grow (&linenumbers, 4);
-  ptr = linenumbers.ptr;
-  PUT2 (pc);
-  PUT2 (line);
-  linenumbers.ptr = ptr;
+  (get_jcf_label_here (state))->linenumber = line;
+  state->linenumber_count++;
 }
+
 \f
 /* The index of jvm local variable allocated for this DECL.
-   This is assign when generating .class files;
-   contrast DECL_LOCAL_SLOT_NUMBER whcih is set when *reading* a .class file.
+   This is assigned when generating .class files;
+   contrast DECL_LOCAL_SLOT_NUMBER which is set when *reading* a .class file.
    (We don't allocate DECL_LANG_SPECIFIC for locals from Java sourc code.) */
 
 #define DECL_LOCAL_INDEX(DECL) DECL_ALIGN(DECL)
 
 struct localvar_info
 {
-  tree decl;
+  struct localvar_info *next;
 
-  int start_pc;
-
-  /* Offset in LocalVariableTable. */
-  int debug_offset;
+  tree decl;
+  struct jcf_block *start_label;
+  struct jcf_block *end_label;
 };
 
-struct buffer localvars = NULL_BUFFER;
-
-#define localvar_buffer ((struct localvar_info*) localvars.data)
-#define localvar_max ((struct localvar_info*) localvars.ptr - localvar_buffer)
-
-/* A buffer for storing LocalVariableTable entries entries. */
-
-struct buffer localvartable = NULL_BUFFER;
+#define localvar_buffer ((struct localvar_info**) state->localvars.data)
+#define localvar_max \
+  ((struct localvar_info**) state->localvars.ptr - localvar_buffer)
 
 int
-localvar_alloc (decl, start_pc)
+localvar_alloc (decl, state)
      tree decl;
-     int start_pc;
+     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 = (struct localvar_info*)localvars.data;
-  register struct localvar_info *limit = (struct localvar_info*)localvars.ptr;
-  for (index = 0;  info < limit;  index++, info++)
+  register struct localvar_info *info;
+  register struct localvar_info **ptr = localvar_buffer;
+  register struct localvar_info **limit
+    = (struct localvar_info**) state->localvars.ptr;
+  for (index = 0;  ptr < limit;  index++, ptr++)
     {
-      if (info->decl == NULL_TREE
-         && (! wide || (info+1)->decl == NULL_TREE))
+      if (ptr[0] == NULL
+         && (! wide || ((ptr+1) < limit && ptr[1] == NULL)))
        break;
     }
-  if (info == limit)
+  if (ptr == limit)
     {
-      buffer_grow (&localvars, sizeof (struct localvar_info));
-      info = (struct localvar_info*)localvars.data + index;
-      localvars.ptr = (unsigned char *) (info + 1 + wide);
+      buffer_grow (&state->localvars, 2 * sizeof (struct localvar_info*));
+      ptr = (struct localvar_info**) state->localvars.data + index;
+      state->localvars.ptr = (unsigned char *) (ptr + 1 + wide);
     }
-  info->decl = decl;
+  info = (struct localvar_info *)
+    obstack_alloc (state->chunk_obstack, sizeof (struct localvar_info));
+  ptr[0] = info;
   if (wide)
-    (info+1)->decl = TYPE_SECOND;
+    ptr[1] = (struct localvar_info *)(~0);
   DECL_LOCAL_INDEX (decl) = index;
-  info->start_pc = start_pc;
+  info->decl = decl;
+  info->start_label = start_label;
 
   if (DECL_NAME (decl) != NULL_TREE)
     {
       /* Generate debugging info. */
-      int i;
-      register unsigned char *ptr;
-      buffer_grow (&localvartable, 10);
-      ptr = localvartable.ptr;
-      info->debug_offset = ptr - localvartable.data;
-      PUT2 (start_pc);
-      PUT2 (0);  /* length - fill in later */
-      i = find_utf8_constant (code_cpool, DECL_NAME (decl));
-      PUT2 (i); /* name_index*/
-      i = find_utf8_constant (code_cpool,
-                             build_java_signature (TREE_TYPE (decl)));
-      PUT2 (i);  /* descriptor_index */
-      PUT2 (index);
-      localvartable.ptr = ptr;
+      info->next = NULL;
+      if (state->last_lvar != NULL)
+       state->last_lvar->next = info;
+      else
+       state->first_lvar = info;
+      state->last_lvar = info;
+      state->lvar_count++;
     }
-  else
-    info->debug_offset = -1;
 }
 
 int
-localvar_free (decl, end_pc)
-     tree decl;
-     int end_pc;
+localvar_free (decl, state)
+     tree decl;     
+     struct jcf_partial *state;
 {
-  register unsigned char *ptr;
+  struct jcf_block *end_label = get_jcf_label_here (state);
   int index = DECL_LOCAL_INDEX (decl);
-  register struct localvar_info *info = &localvar_buffer [index];
+  register struct localvar_info **ptr = &localvar_buffer [index];
+  register struct localvar_info *info = *ptr;
   int wide = TYPE_IS_WIDE (TREE_TYPE (decl));
   int i;
 
-  i = info->debug_offset;
-  if (i >= 0)
-    {
-      register unsigned char *ptr;
-      /* Point to length field of local_variable_table. */
-      ptr = localvartable.data + i + 2;
-      i = end_pc - info->start_pc;
-      PUT2 (i);
-    }
+  info->end_label = end_label;
 
   if (info->decl != decl)
     abort ();
-  info->decl = NULL_TREE;
+  ptr[0] = NULL;
   if (wide)
     {
-      info++;
-      if (info->decl != TYPE_SECOND)
+      if (ptr[1] !=  (struct localvar_info *)(~0))
        abort ();
-      info->decl = NULL_TREE;
+      ptr[1] = NULL;
     }
-
 }
 
 \f
 #define STACK_TARGET 1
 #define IGNORE_TARGET 2
 
-/* 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 *
-alloc_chunk (last, data, size, work)
-     struct chunk *last;
-     unsigned char *data;
-     int size;
-     struct obstack *work;
-{
-  struct chunk *chunk = (struct chunk *)
-    obstack_alloc (work, sizeof(struct chunk));
-
-  if (data == NULL && size > 0)
-    data = obstack_alloc (work, size);
-
-  chunk->next = NULL;
-  chunk->data = data;
-  chunk->size = size;
-  last->next = chunk;
-  return chunk;
-}
-
 /* 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. */
 
@@ -327,9 +489,10 @@ write_chunks (stream, chunks)
     fwrite (chunks->data, chunks->size, 1, stream);
 }
 
-void
-push_constant1 (index)
+static void
+push_constant1 (index, state)
      int index;
+     struct jcf_partial *state;
 {
   if (index < 256)
     {
@@ -343,18 +506,23 @@ push_constant1 (index)
     }
 }
 
-void
-push_constant2 (index)
+static void
+push_constant2 (index, state)
      int index;
+     struct jcf_partial *state;
 {
   RESERVE (3);
   OP1 (OPCODE_ldc2_w);
   OP2 (index);
 }
 
-void
-push_int_const (i)
+/* Push 32-bit integer constant on VM stack.
+   Caller is responsible for doing NOTE_PUSH. */
+
+static void
+push_int_const (i, state)
      HOST_WIDE_INT i;
+     struct jcf_partial *state;
 {
   RESERVE(3);
   if (i >= -1 && i <= 5)
@@ -368,17 +536,22 @@ push_int_const (i)
     {
       OP1(OPCODE_sipush);
       OP2(i);
+      NOTE_PUSH (1);
     }
   else
     {
-      i = find_constant1 (code_cpool, CONSTANT_Integer, i & 0xFFFFFFFF);
+      i = find_constant1 (&state->cpool, CONSTANT_Integer, i & 0xFFFFFFFF);
       push_constant1 (i);
     }
 }
 
-void
-push_long_const (lo, hi)
+/* Push 64-bit long constant on VM stack.
+   Caller is responsible for doing NOTE_PUSH. */
+
+static void
+push_long_const (lo, hi, state)
      HOST_WIDE_INT lo, hi;
+     struct jcf_partial *state;
 {
   if (hi == 0 && lo >= 0 && lo <= 1)
     {
@@ -388,7 +561,7 @@ push_long_const (lo, hi)
 #if 0
     else if ((jlong) (jint) i == i)
       {
-        push_int_const ((jint) i);
+        push_int_const ((jint) i, state);
         RESERVE (1);
         OP1 (OPCODE_i2l);
       }
@@ -397,18 +570,19 @@ push_long_const (lo, hi)
     {
       HOST_WIDE_INT w1, w2;
       lshift_double (lo, hi, -32, 64, &w1, &w2, 1);
-      hi = find_constant1 (code_cpool, CONSTANT_Long,
+      hi = find_constant1 (&state->cpool, CONSTANT_Long,
                           w1 & 0xFFFFFFFF, lo & 0xFFFFFFFF);
       push_constant2 (hi);
     }
 }
 
-void
-field_op (field, opcode)
+static void
+field_op (field, opcode, state)
      tree field;
      int opcode;
+     struct jcf_partial *state;
 {
-  int index = find_fieldref_index (code_cpool, field);
+  int index = find_fieldref_index (&state->cpool, field);
   RESERVE (3);
   OP1 (opcode);
   OP2 (index);
@@ -424,10 +598,12 @@ adjust_typed_op (type)
 {
   switch (TREE_CODE (type))
     {
-    case BOOLEAN_TYPE:  return 5;
-    case CHAR_TYPE:     return 6;
     case POINTER_TYPE:
     case RECORD_TYPE:   return 4;
+    case BOOLEAN_TYPE:
+      return TYPE_PRECISION (type) == 32 ? 0 : 5;
+    case CHAR_TYPE:
+      return TYPE_PRECISION (type) == 32 ? 0 : 6;
     case INTEGER_TYPE:
       switch (TYPE_PRECISION (type))
        {
@@ -448,14 +624,15 @@ adjust_typed_op (type)
   abort ();
 }
 
-void
-maybe_wide (opcode, index)
+static void
+maybe_wide (opcode, index, state)
      int opcode, index;
+     struct jcf_partial *state;
 {
   if (index >= 256)
     {
       RESERVE (4);
-      OP1 (196); /* wide */
+      OP1 (OPCODE_wide);
       OP1 (opcode);
       OP2 (index);
     }
@@ -467,21 +644,382 @@ maybe_wide (opcode, index)
     }
 }
 
-#define PC BUFFER_LENGTH(&bytecode)
+/* Compile code to duplicate with offset, where
+   SIZE is the size of the stack item to duplicate (1 or 2), abd
+   OFFSET is where to insert the result (must be 0, 1, or 2).
+   (The new words get inserted at stack[SP-size-offset].) */
 
-/* Generate byetcode for sub-expression EXP of METHOD.
-   TARGET is one of STACK_TARGET or IGNORE_TARGET. */
+static void
+emit_dup (size, offset, state)
+     int size, offset;
+     struct jcf_partial *state;
+{
+  int kind;
+  if (size == 0)
+    return;
+  RESERVE(1);
+  if (offset == 0)
+    kind = size == 1 ? OPCODE_dup : OPCODE_dup2;
+  else if (offset == 1)
+    kind = size == 1 ? OPCODE_dup_x1 : OPCODE_dup2_x1;
+  else if (offset == 2)
+    kind = size == 1 ? OPCODE_dup_x2 : OPCODE_dup2_x2;
+  else
+    abort();
+  OP1 (kind);
+  NOTE_PUSH (size);
+}
+
+static void
+emit_pop (size, state)
+     int size;
+     struct jcf_partial *state;
+{
+  RESERVE (1);
+  OP1 (OPCODE_pop - 1 + size);
+}
+
+static void
+emit_iinc (var, value, state)
+     tree var;
+     int value;
+     struct jcf_partial *state;
+{
+  int slot = DECL_LOCAL_INDEX (var);
+
+  if (value < -128 || value > 127 || slot >= 256)
+    {
+      RESERVE (6);
+      OP1 (OPCODE_wide);
+      OP1 (OPCODE_iinc);
+      OP2 (slot);
+      OP2 (value);
+    }
+  else
+    {
+      RESERVE (3);
+      OP1 (OPCODE_iinc);
+      OP1 (slot);
+      OP1 (value);
+    }
+}
+
+static void
+emit_load_or_store (var, opcode, state)
+     tree var;
+     struct jcf_partial *state;
+{
+  tree type = TREE_TYPE (var);
+  int kind = adjust_typed_op (type);
+  int index = DECL_LOCAL_INDEX (var);
+  if (index <= 3)
+    {
+      RESERVE (1);
+      OP1 (opcode + 5 + 4 * kind + index);    /* [ilfda]{load,store}_[0123] */
+    }
+  else
+    maybe_wide (opcode + kind, index);  /* [ilfda]{load,store} */
+}
+
+static void
+emit_load (var, state)
+     tree var;
+     struct jcf_partial *state;
+{
+  emit_load_or_store (var, OPCODE_iload, state);
+  NOTE_PUSH (TYPE_IS_WIDE (TREE_TYPE (var)) ? 2 : 1);
+}
+
+static void
+emit_store (var, state)
+     tree var;
+     struct jcf_partial *state;
+{
+  emit_load_or_store (var, OPCODE_istore, state);
+  NOTE_POP (TYPE_IS_WIDE (TREE_TYPE (var)) ? 2 : 1);
+}
+
+static void
+emit_binop (opcode, type, state)
+     enum java_opcode opcode;
+     tree type;
+     struct jcf_partial *state;
+{
+  int size = TYPE_IS_WIDE (type) ? 2 : 1;
+  RESERVE(1);
+  OP1 (opcode);
+  NOTE_POP (size);
+}
+
+/* Emit a conditional jump to TARGET with a 2-byte relative jump offset
+   The opcode is OPCODE, the inverted opcode is INV_OPCODE. */
+
+static void
+emit_if (target, opcode, inv_opcode, state)
+     struct jcf_block *target;
+     int opcode, inv_opcode;
+     struct jcf_partial *state;
+{
+  struct jcf_relocation *reloc = (struct jcf_relocation *)
+    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;
+  OP1 (opcode);
+  reloc->offset = BUFFER_LENGTH (&state->bytecode);
+  OP2 (1); // 1 byte from reloc back to start of instruction.
+  reloc->kind = - inv_opcode;
+  reloc->label = target;
+}
+
+static void
+emit_goto_or_jsr (target, opcode, opcode_w, state)
+     struct jcf_block *target;
+     int opcode, opcode_w;
+     struct jcf_partial *state;
+{
+  struct jcf_relocation *reloc = (struct jcf_relocation *)
+    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;
+  OP1 (opcode);
+  reloc->offset = BUFFER_LENGTH (&state->bytecode);
+  OP2 (1); // 1 byte from reloc back to start of instruction.
+  reloc->kind = opcode_w;
+  reloc->label = target;
+}
+
+static void
+emit_goto (target, state)
+     struct jcf_block *target;
+     struct jcf_partial *state;
+{
+  emit_goto_or_jsr (target, OPCODE_goto, OPCODE_goto_w, state);
+}
+
+static void
+emit_jsr (target, state)
+     struct jcf_block *target;
+     struct jcf_partial *state;
+{
+  emit_goto_or_jsr (target, OPCODE_jsr, OPCODE_jsr_w, state);
+}
+
+/* Generate code to evaluate EXP.  If the result is true,
+   branch to TRUE_LABEL; otherwise, branch to FALSE_LABEL.
+   TRUE_BRANCH_FIRST is a code geneation hint that the
+   TRUE_LABEL may follow right after this. (The idea is that we
+   may be able to optimize away GOTO TRUE_LABEL; TRUE_LABEL:) */
 
 void
-generate_bytecode_insns (method, exp, target)
-     tree method;
+generate_bytecode_conditional (exp, true_label, false_label,
+                              true_branch_first, state)
+     tree exp;
+     struct jcf_block *true_label;
+     struct jcf_block *false_label;
+     int true_branch_first;
+     struct jcf_partial *state;
+{
+  int kind;
+  tree exp0, exp1, type;
+  int save_SP = state->code_SP;
+  enum java_opcode op, negop;
+  switch (TREE_CODE (exp))
+    {
+    case INTEGER_CST:
+      emit_goto (integer_zerop (exp) ? false_label : true_label, state);
+      break;
+    case COND_EXPR:
+      {
+       struct jcf_block *then_label = gen_jcf_label (state);
+       struct jcf_block *else_label = gen_jcf_label (state);
+       int save_SP_before, save_SP_after;
+       generate_bytecode_conditional (TREE_OPERAND (exp, 0),
+                                      then_label, else_label, 1, state);
+       define_jcf_label (then_label, state);
+       save_SP_before = state->code_SP;
+       generate_bytecode_conditional (TREE_OPERAND (exp, 1),
+                                      true_label, false_label, 1, state);
+       save_SP_after = state->code_SP;
+       state->code_SP = save_SP_before;
+       define_jcf_label (else_label, state);
+       generate_bytecode_conditional (TREE_OPERAND (exp, 2),
+                                      true_label, false_label,
+                                      true_branch_first, state);
+       if (state->code_SP != save_SP_after)
+         fatal ("internal error  non-matching SP");
+      }
+      break;
+    case TRUTH_ANDIF_EXPR:
+      {
+       struct jcf_block *next_label = gen_jcf_label (state);
+       generate_bytecode_conditional (TREE_OPERAND (exp, 0),
+                                      next_label, false_label, 1, state);
+       define_jcf_label (next_label, state);
+       generate_bytecode_conditional (TREE_OPERAND (exp, 1),
+                                      true_label, false_label, 1, state);
+      }
+      break;
+    case TRUTH_ORIF_EXPR:
+      {
+       struct jcf_block *next_label = gen_jcf_label (state);
+       generate_bytecode_conditional (TREE_OPERAND (exp, 0),
+                                      true_label, next_label, 1, state);
+       define_jcf_label (next_label, state);
+       generate_bytecode_conditional (TREE_OPERAND (exp, 1),
+                                      true_label, false_label, 1, state);
+      }
+      break;
+    compare_1:
+      /* Assuming op is one of the 2-operand if_icmp<COND> instructions,
+        set it to the corresponding 1-operand if<COND> instructions. */
+      op = op - 6;
+      /* FALLTHROUGH */
+    compare_2:
+      /* The opcodes with their inverses are allocated in pairs.
+        E.g.  The inverse of if_icmplt (161) is if_icmpge (162). */
+      negop = (op & 1) ? op + 1 : op - 1;
+    compare_2_ptr:
+      if (true_branch_first)
+       {
+         emit_if (false_label, negop, op, state);
+         emit_goto (true_label, state);
+       }
+      else
+       {
+         emit_if (true_label, op, negop, state);
+         emit_goto (false_label, state);
+       }
+      break;
+    case EQ_EXPR:
+      op = OPCODE_if_icmpeq;
+      goto compare;
+    case NE_EXPR:
+      op = OPCODE_if_icmpne;
+      goto compare;
+    case GT_EXPR:
+      op = OPCODE_if_icmpgt;
+      goto compare;
+    case LT_EXPR:
+      op = OPCODE_if_icmplt;
+      goto compare;
+    case GE_EXPR:
+      op = OPCODE_if_icmpge;
+      goto compare;
+    case LE_EXPR:
+      op = OPCODE_if_icmple;
+      goto compare;
+    compare:
+      exp0 = TREE_OPERAND (exp, 0);
+      exp1 = TREE_OPERAND (exp, 1);
+      type = TREE_TYPE (exp0);
+      switch (TREE_CODE (type))
+       {
+       case POINTER_TYPE:  case RECORD_TYPE:
+         switch (TREE_CODE (exp))
+           {
+           case EQ_EXPR:  op = OPCODE_if_acmpeq;  break;
+           case NE_EXPR:  op = OPCODE_if_acmpne;  break;
+           default:  abort();
+           }
+         if (integer_zerop (exp1) || integer_zerop (exp0))
+           {
+             generate_bytecode_insns (integer_zerop (exp1) ? exp0 : exp0,
+                                      STACK_TARGET, state);
+             op = op + (OPCODE_ifnull - OPCODE_if_acmpeq);
+             negop = (op & 1) ? op - 1 : op + 1;
+             NOTE_POP (1);
+             goto compare_2_ptr;
+           }
+         generate_bytecode_insns (exp0, STACK_TARGET, state);
+         generate_bytecode_insns (exp1, STACK_TARGET, state);
+         NOTE_POP (2);
+         goto compare_2;
+       case REAL_TYPE:
+         fatal ("float comparison not implemented");
+       case INTEGER_TYPE:
+         if (TYPE_PRECISION (type) > 32)
+           {
+             generate_bytecode_insns (exp0, STACK_TARGET, state);
+             generate_bytecode_insns (exp1, STACK_TARGET, state);
+             NOTE_POP (4);
+             RESERVE (1);
+             OP1 (OPCODE_lcmp);
+             goto compare_1;
+           }
+         /* FALLTHOUGH */
+       default:
+         if (integer_zerop (exp1))
+           {
+             generate_bytecode_insns (exp0, STACK_TARGET, state);
+             NOTE_POP (1);
+             goto compare_1;
+           }
+         if (integer_zerop (exp0))
+           {
+             switch (op)
+               {
+               case OPCODE_if_icmplt:
+               case OPCODE_if_icmpge:
+                 op += 2;
+                 break;
+               case OPCODE_if_icmpgt:
+               case OPCODE_if_icmple:
+                 op -= 2;
+                 break;
+               }
+             generate_bytecode_insns (exp1, STACK_TARGET, state);
+             NOTE_POP (1);
+             goto compare_1;
+           }
+         generate_bytecode_insns (exp0, STACK_TARGET, state);
+         generate_bytecode_insns (exp1, STACK_TARGET, state);
+         NOTE_POP (2);
+         goto compare_2;
+       }
+
+    default:
+      generate_bytecode_insns (exp, STACK_TARGET, state);
+      NOTE_POP (1);
+      if (true_branch_first)
+       {
+         emit_if (false_label, OPCODE_ifeq, OPCODE_ifne, state);
+         emit_goto (true_label, state);
+       }
+      else
+       {
+         emit_if (true_label, OPCODE_ifne, OPCODE_ifeq, state);
+         emit_goto (false_label, state);
+       }
+      break;
+    }
+  if (save_SP != state->code_SP)
+    fatal ("inetrnal error - SP mismatch");
+}
+
+/* Generate bytecode for sub-expression EXP of METHOD.
+   TARGET is one of STACK_TARGET or IGNORE_TARGET. */
+
+static void
+generate_bytecode_insns (exp, target, state)
      tree exp;
      int target;
+     struct jcf_partial *state;
 {
-  rtx value;
-  tree type = TREE_TYPE (exp);
+  tree type;
   enum java_opcode jopcode;
   int op;
+  HOST_WIDE_INT value;
+  int post_op;
+  int size;
+  int offset;
+
+  if (exp == NULL && target == IGNORE_TARGET)
+    return;
+
+  type = TREE_TYPE (exp);
+
   switch (TREE_CODE (exp))
     {
     case BLOCK:
@@ -491,21 +1029,21 @@ generate_bytecode_insns (method, exp, target)
          for (local = BLOCK_EXPR_DECLS (exp); local; )
            {
              tree next = TREE_CHAIN (local);
-             localvar_alloc (local, PC);
+             localvar_alloc (local, state);
              local = next;
            }
-         generate_bytecode_insns (method, BLOCK_EXPR_BODY (exp), target);
+         generate_bytecode_insns (BLOCK_EXPR_BODY (exp), target, state);
          for (local = BLOCK_EXPR_DECLS (exp); local; )
            {
              tree next = TREE_CHAIN (local);
-             localvar_free (local, PC);
+             localvar_free (local, state);
              local = next;
            }
        }
       break;
       case COMPOUND_EXPR:      
-       generate_bytecode_insns (method, TREE_OPERAND (exp, 0), IGNORE_TARGET);
-       generate_bytecode_insns (method, TREE_OPERAND (exp, 1), target);
+       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:
       {
@@ -514,8 +1052,8 @@ generate_bytecode_insns (method, exp, target)
        input_filename = EXPR_WFL_FILENAME (exp);
        lineno = EXPR_WFL_LINENO (exp);
        if (EXPR_WFL_EMIT_LINE_NOTE (exp))
-         put_linenumber (PC, EXPR_WFL_LINENO (exp));
-       generate_bytecode_insns (method, EXPR_WFL_NODE (exp), target);
+         put_linenumber (EXPR_WFL_LINENO (exp), state);
+       generate_bytecode_insns (EXPR_WFL_NODE (exp), target, state);
        input_filename = saved_input_filename;
        lineno = saved_lineno;
       }
@@ -532,46 +1070,39 @@ generate_bytecode_insns (method, exp, target)
        }
       else if (TYPE_PRECISION (type) <= 32)
        {
-         push_int_const (TREE_INT_CST_LOW (exp));
+         push_int_const (TREE_INT_CST_LOW (exp), state);
          NOTE_PUSH (1);
        }
       else
        {
-         push_long_const (TREE_INT_CST_LOW (exp), TREE_INT_CST_HIGH (exp));
+         push_long_const (TREE_INT_CST_LOW (exp), TREE_INT_CST_HIGH (exp),
+                          state);
          NOTE_PUSH (2);
        }
       break;
     case VAR_DECL:
       if (TREE_STATIC (exp))
        {
-         field_op (exp, OPCODE_getstatic);
+         field_op (exp, OPCODE_getstatic, state);
+         NOTE_PUSH (TYPE_IS_WIDE (TREE_TYPE (exp)) ? 2 : 1);
          break;
        }
       /* ... fall through ... */
     case PARM_DECL:
-      {
-       int kind = adjust_typed_op (type);
-       int index = DECL_LOCAL_INDEX (exp);
-       if (index <= 3)
-         {
-           RESERVE (1);
-           OP1 (26 + 4 * kind + index);    /* [ilfda]load_[0123] */
-         }
-       else
-         maybe_wide (21 + kind, index);  /* [ilfda]load */
-      }
+      emit_load (exp, state);
       break;
     case INDIRECT_REF:
-      generate_bytecode_insns (method, TREE_OPERAND (exp, 0), target);
+      generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state);
       break;
     case ARRAY_REF:
-      generate_bytecode_insns (method, TREE_OPERAND (exp, 0), target);
-      generate_bytecode_insns (method, TREE_OPERAND (exp, 1), target);
+      generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state);
+      generate_bytecode_insns (TREE_OPERAND (exp, 1), target, state);
       if (target != IGNORE_TARGET)
        {
          jopcode = OPCODE_iaload + adjust_typed_op (type);
          RESERVE(1);
          OP1 (jopcode);
+         NOTE_POP (2);
        }
       break;
     case COMPONENT_REF:
@@ -579,8 +1110,8 @@ generate_bytecode_insns (method, exp, target)
        tree obj = TREE_OPERAND (exp, 0);
        tree field = TREE_OPERAND (exp, 1);
        int is_static = FIELD_STATIC (field);
-       generate_bytecode_insns (method, obj,
-                                is_static ? IGNORE_TARGET : target);
+       generate_bytecode_insns (obj,
+                                is_static ? IGNORE_TARGET : target, state);
        if (target != IGNORE_TARGET)
          {
            if (DECL_NAME (field) == length_identifier_node && !is_static
@@ -590,10 +1121,54 @@ generate_bytecode_insns (method, exp, target)
                OP1 (OPCODE_arraylength);
              }
            else
-             field_op (field, is_static ? OPCODE_getstatic : OPCODE_getfield);
+             {
+               field_op (field, is_static ? OPCODE_getstatic : OPCODE_getfield,
+                         state);
+               if (! is_static)
+                 NOTE_POP (1);
+               NOTE_PUSH (TYPE_IS_WIDE (TREE_TYPE (field)) ? 2 : 1);
+             }
          }
       }
       break;
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
+    case EQ_EXPR:
+    case NE_EXPR:
+    case GT_EXPR:
+    case LT_EXPR:
+    case GE_EXPR:
+    case LE_EXPR:
+      {
+       struct jcf_block *then_label = gen_jcf_label (state);
+       struct jcf_block *else_label = gen_jcf_label (state);
+       struct jcf_block *end_label = gen_jcf_label (state);
+       generate_bytecode_conditional (exp,
+                                      then_label, else_label, 1, state);
+       define_jcf_label (then_label, state);
+       push_int_const (1, state);
+       emit_goto (end_label, state);
+       define_jcf_label (else_label, state);
+       push_int_const (0, state);
+       define_jcf_label (end_label, state);
+       NOTE_PUSH (1);
+      }
+      break;
+    case COND_EXPR:
+      {
+       struct jcf_block *then_label = gen_jcf_label (state);
+       struct jcf_block *else_label = gen_jcf_label (state);
+       struct jcf_block *end_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_insns (TREE_OPERAND (exp, 1), target, state);
+       emit_goto (end_label, state);
+       define_jcf_label (else_label, state);
+       generate_bytecode_insns (TREE_OPERAND (exp, 2), target, state);
+       define_jcf_label (end_label, state);
+      }
+      break;
     case RETURN_EXPR:
       if (!TREE_OPERAND (exp, 0))
        op = OPCODE_return;
@@ -604,89 +1179,234 @@ generate_bytecode_insns (method, exp, target)
            abort ();
          exp = TREE_OPERAND (exp, 1);
          op = OPCODE_ireturn + adjust_typed_op (TREE_TYPE (exp));
-         generate_bytecode_insns (method, exp, STACK_TARGET);
+         generate_bytecode_insns (exp, STACK_TARGET, state);
        }
       RESERVE (1);
       OP1 (op);
       break;
-    case MODIFY_EXPR:
+    case LABELED_BLOCK_EXPR:
       {
-       tree lhs = TREE_OPERAND (exp, 0);
-       tree rhs = TREE_OPERAND (exp, 1);
-       HOST_WIDE_INT value;
+       struct jcf_block *end_label = gen_jcf_label (state);
+       end_label->next = state->labeled_blocks;
+       state->labeled_blocks = end_label;
+       end_label->u.labeled_block = exp;
+       if (LABELED_BLOCK_BODY (exp))
+         generate_bytecode_insns (LABELED_BLOCK_BODY (exp), target, state);
+       if (state->labeled_blocks != end_label)
+         abort();
+       state->labeled_blocks = end_label->next;
+       define_jcf_label (end_label, state);
+      }
+      break;
+    case LOOP_EXPR:
+      {
+       tree body = TREE_OPERAND (exp, 0);
 #if 0
-       if (TREE_CODE (rhs) == PLUS_EXPR
-           && TREE_CODE (lhs) == VAR_DECL
-           /* && FIXME lhs is a local variable */
-           && TYPE_MODE (TREE)TYPE (lhs) == SImode /* ??? */
-           && TREE_OPERAND (rhs, 0) == lhs
-           && TREE_CODE (TREE_OPERAND (rhs, 1)) == INTEGER_CST
-           /* or vice versa FIXME */
-           && (value = TREE_INT_CST_LOW (TREE_OPERAND (rhs, 1)),
-               (value >= -32768 && value <= 32767)))
+       if (TREE_CODE (body) == COMPOUND_EXPR
+           && TREE_CODE (TREE_OPERAND (body, 0)) == EXIT_EXPR)
          {
-           emit_insn (gen_rtx (SET, SImode,
-                               DECL_RTL (lhs),
-                               gen_rtx (PLUS, SImode,
-                                        DECL_RTL (lhs),
-                                        gen_rtx_CONST_INT (SImode, value))));
-           return DECL_RTL (lhs);
+           /* Optimize:  H: if (TEST) GOTO L; BODY; GOTO H; L:
+              to:  GOTO L;  BODY;  L:  if (!TEST) GOTO L; */
+           struct jcf_block *head_label;
+           struct jcf_block *body_label;
+           struct jcf_block *end_label = gen_jcf_label (state);
+           struct jcf_block *exit_label = state->labeled_blocks;
+           head_label = gen_jcf_label (state);
+           emit_goto (head_label, state);
+           body_label = get_jcf_label_here (state);
+           generate_bytecode_insns (TREE_OPERAND (body, 1), target, state);
+           define_jcf_label (head_label, state);
+           generate_bytecode_conditional (TREE_OPERAND (body, 0),
+                                          end_label, body_label, 1, state);
+           define_jcf_label (end_label, state);
          }
+       else
 #endif
-       if (TREE_CODE (lhs) == COMPONENT_REF)
-         generate_bytecode_insns (method, TREE_OPERAND (lhs, 0), STACK_TARGET);
-       else if (TREE_CODE (lhs) == ARRAY_REF)
-         {
-           generate_bytecode_insns (method,
-                                    TREE_OPERAND (lhs, 0), STACK_TARGET);
-           generate_bytecode_insns (method,
-                                    TREE_OPERAND (lhs, 1), STACK_TARGET);
-         }
-       generate_bytecode_insns (method, rhs, STACK_TARGET);
-       if (target != IGNORE_TARGET)
-         {
-           RESERVE (1);
-           OP1 (TYPE_IS_WIDE (type) ? OPCODE_dup2_x1 : OPCODE_dup_x1);
-         }
-       if (TREE_CODE (lhs) == COMPONENT_REF)
          {
-           tree field = TREE_OPERAND (lhs, 1);
-           field_op (field,
-                     FIELD_STATIC (field) ? OPCODE_putstatic
-                     : OPCODE_putfield);
+           struct jcf_block *head_label = get_jcf_label_here (state);
+           generate_bytecode_insns (body, IGNORE_TARGET, state);
+           emit_goto (head_label, state);
          }
-       else if (TREE_CODE (lhs) == VAR_DECL
-                || TREE_CODE (lhs) == PARM_DECL)
+      }
+      break;
+    case EXIT_EXPR:
+      {
+       struct jcf_block *label = state->labeled_blocks;
+       struct jcf_block *end_label = gen_jcf_label (state);
+       generate_bytecode_conditional (TREE_OPERAND (exp, 0),
+                                      label, end_label, 0, state);
+       define_jcf_label (end_label, state);
+      }
+      break;
+    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))
+         label = label->next;
+       emit_goto (label, state);
+      }
+      break;
+
+    case PREDECREMENT_EXPR:  value = -1; post_op = 0;  goto increment;
+    case PREINCREMENT_EXPR:  value =  1; post_op = 0;  goto increment;
+    case POSTDECREMENT_EXPR: value = -1; post_op = 1;  goto increment;
+    case POSTINCREMENT_EXPR: value =  1; post_op = 1;  goto increment;
+    increment:
+
+      exp = TREE_OPERAND (exp, 0);
+      type = TREE_TYPE (exp);
+      size = TYPE_IS_WIDE (type) ? 2 : 1;
+      if ((TREE_CODE (exp) == VAR_DECL || TREE_CODE (exp) == PARM_DECL)
+         && ! TREE_STATIC (exp)
+         && TREE_CODE (type) == INTEGER_TYPE
+         && TYPE_PRECISION (type) == 32)
+       {
+         if (target != IGNORE_TARGET && post_op)
+           emit_load (exp, state);
+         emit_iinc (exp, value, state);
+         if (target != IGNORE_TARGET)
+           {
+             if (! post_op)
+               emit_load (exp, state);
+             NOTE_PUSH (1);
+           }
+         break;
+       }
+      if (TREE_CODE (exp) == COMPONENT_REF)
+       {
+         generate_bytecode_insns (TREE_OPERAND (exp, 0), STACK_TARGET, state);
+         emit_dup (1, 0, state);
+         /* Stack:  ..., objectref, objectref. */
+         field_op (TREE_OPERAND (exp, 1), OPCODE_getstatic, state);
+         NOTE_PUSH (size);
+         /* Stack:  ..., objectref, oldvalue. */
+         offset = 1;
+       }
+      else if (TREE_CODE (exp) == ARRAY_REF)
+       {
+         generate_bytecode_insns (TREE_OPERAND (exp, 0), STACK_TARGET, state);
+         generate_bytecode_insns (TREE_OPERAND (exp, 1), STACK_TARGET, state);
+         emit_dup (2, 0, state);
+         /* Stack:  ..., array, index, array, index. */
+         jopcode = OPCODE_iaload + adjust_typed_op (TREE_TYPE (exp));
+         RESERVE(1);
+         OP1 (jopcode);
+         NOTE_POP (2-size);
+         /* Stack:  ..., array, index, oldvalue. */
+         offset = 2;
+       }
+      else if (TREE_CODE (exp) == VAR_DECL || TREE_CODE (exp) == PARM_DECL)
+       {
+         generate_bytecode_insns (exp, STACK_TARGET, state);
+         /* Stack:  ..., oldvalue. */
+         offset = 0;
+       }
+      else
+       abort ();
+
+      if (target != IGNORE_TARGET && post_op)
+       emit_dup (size, offset, state);
+      /* Stack, if ARRAY_REF:  ..., [result, ] array, index, oldvalue. */
+      /* Stack, if COMPONENT_REF:  ..., [result, ] objectref, oldvalue. */
+      /* Stack, otherwise:  ..., [result, ] oldvalue. */
+      push_int_const (value, state); /* FIXME - assumes int! */
+      NOTE_PUSH (1);
+      emit_binop (OPCODE_iadd + adjust_typed_op (type), type, state);
+      if (target != IGNORE_TARGET && ! post_op)
+       emit_dup (size, offset, state);
+      /* Stack:  ..., [result,] newvalue. */
+      goto finish_assignment;
+
+    case MODIFY_EXPR:
+      {
+       tree lhs = TREE_OPERAND (exp, 0);
+       tree rhs = TREE_OPERAND (exp, 1);
+
+       /* See if we can use the iinc instruction. */
+       if ((TREE_CODE (lhs) == VAR_DECL || TREE_CODE (lhs) == PARM_DECL)
+           && ! TREE_STATIC (lhs)
+           && TREE_CODE (TREE_TYPE (lhs)) == INTEGER_TYPE
+           && TYPE_PRECISION (TREE_TYPE (lhs)) == 32
+           && (TREE_CODE (rhs) == PLUS_EXPR || TREE_CODE (rhs) == MINUS_EXPR))
          {
-           if (FIELD_STATIC (lhs))
+           tree arg0 = TREE_OPERAND (rhs, 0);
+           tree arg1 = TREE_OPERAND (rhs, 1);
+           HOST_WIDE_INT min_value = -32768;
+           HOST_WIDE_INT max_value = 32767;
+           if (TREE_CODE (rhs) == MINUS_EXPR)
              {
-               field_op (lhs, OPCODE_putstatic);
+               min_value++;
+               max_value++;
              }
-           else
+           else if (arg1 == lhs)
              {
-               int index = DECL_LOCAL_INDEX (lhs);
-               int opcode = adjust_typed_op (TREE_TYPE (lhs));
-               if (index <= 3)
-                 {
-                   RESERVE (1);
-                   opcode = 59 + 4 * opcode + index;
-                   OP1 (opcode);  /* [ilfda]store_[0123] */
-                 }
-               else
+               arg0 = arg1;
+               arg1 = TREE_OPERAND (rhs, 0);
+             }
+           if (lhs == arg0 && TREE_CODE (arg1) == INTEGER_CST)
+             {
+               HOST_WIDE_INT hi_value = TREE_INT_CST_HIGH (arg1);
+               value = TREE_INT_CST_LOW (arg1);
+               if ((hi_value == 0 && value <= max_value)
+                   || (hi_value == -1 && value >= min_value))
                  {
-                   maybe_wide (54 + opcode, index);  /* [ilfda]store */
+                   if (TREE_CODE (rhs) == MINUS_EXPR)
+                     value = -value;
+                   emit_iinc (lhs, value, state);
+                   break;
                  }
              }
          }
+
+       if (TREE_CODE (lhs) == COMPONENT_REF)
+         generate_bytecode_insns (TREE_OPERAND (lhs, 0), STACK_TARGET, state);
        else if (TREE_CODE (lhs) == ARRAY_REF)
          {
-           jopcode = OPCODE_iastore + adjust_typed_op (TREE_TYPE (lhs));
-           RESERVE(1);
-           OP1 (jopcode);
+           generate_bytecode_insns (TREE_OPERAND(lhs, 0), STACK_TARGET, state);
+           generate_bytecode_insns (TREE_OPERAND(lhs, 1), STACK_TARGET, state);
          }
-       else
-         fatal ("internal error (bad lhs to MODIFY_EXPR)");
+       generate_bytecode_insns (rhs, STACK_TARGET, state);
+       if (target != IGNORE_TARGET)
+         emit_dup (TYPE_IS_WIDE (type) ? 2 : 1 , 1, state);
+       exp = lhs;
       }
+      /* FALLTHOUGH */
+
+    finish_assignment:
+      if (TREE_CODE (exp) == COMPONENT_REF)
+       {
+         tree field = TREE_OPERAND (exp, 1);
+         if (! FIELD_STATIC (field))
+           NOTE_POP (1);
+         field_op (field,
+                   FIELD_STATIC (field) ? OPCODE_putstatic
+                   : OPCODE_putfield,
+                   state);
+
+         NOTE_PUSH (TYPE_IS_WIDE (TREE_TYPE (field)) ? 2 : 1);
+       }
+      else if (TREE_CODE (exp) == VAR_DECL
+              || TREE_CODE (exp) == PARM_DECL)
+       {
+         if (FIELD_STATIC (exp))
+           {
+             field_op (exp, OPCODE_putstatic, state);
+             NOTE_PUSH (TYPE_IS_WIDE (TREE_TYPE (exp)) ? 2 : 1);
+           }
+         else
+           emit_store (exp, state);
+       }
+      else if (TREE_CODE (exp) == ARRAY_REF)
+       {
+         NOTE_POP (2);
+         jopcode = OPCODE_iastore + adjust_typed_op (TREE_TYPE (exp));
+         RESERVE(1);
+         OP1 (jopcode);
+         NOTE_PUSH (TYPE_IS_WIDE (TREE_TYPE (exp)) ? 2 : 1);
+       }
+      else
+       fatal ("internal error (bad lhs to MODIFY_EXPR)");
       break;
     case PLUS_EXPR:
       jopcode = OPCODE_iadd + adjust_typed_op (type);
@@ -702,25 +1422,24 @@ generate_bytecode_insns (method, exp, target)
       jopcode = OPCODE_idiv + adjust_typed_op (type);
       goto binop;
     binop:
-      generate_bytecode_insns (method, TREE_OPERAND (exp, 0), target);
-      generate_bytecode_insns (method, TREE_OPERAND (exp, 1), target);
+      generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state);
+      generate_bytecode_insns (TREE_OPERAND (exp, 1), target, state);
       if (target == STACK_TARGET)
-       {
-         RESERVE(1);
-         OP1 (jopcode);
-       }
+       emit_binop (jopcode, type, state);
       break;
     case CALL_EXPR:
       {
        tree t;
+       int save_SP = state->code_SP;
        for (t = TREE_OPERAND (exp, 1);  t != NULL_TREE;  t = TREE_CHAIN (t))
          {
-           generate_bytecode_insns (method, TREE_VALUE (t), STACK_TARGET);
+           generate_bytecode_insns (TREE_VALUE (t), STACK_TARGET, state);
          }
        t = TREE_OPERAND (exp, 0);
+       state->code_SP = save_SP;
        if (TREE_CODE (t) == FUNCTION_DECL)
          {
-           int index = find_methodref_index (code_cpool, t);
+           int index = find_methodref_index (&state->cpool, t);
            RESERVE (3);
            if (DECL_CONSTRUCTOR_P (t))
              OP1 (OPCODE_invokespecial);
@@ -729,59 +1448,232 @@ generate_bytecode_insns (method, exp, target)
            else
              OP1 (OPCODE_invokevirtual);
            OP2 (index);
+           t = TREE_TYPE (TREE_TYPE (t));
+           if (TREE_CODE (t) != VOID_TYPE)
+             {
+               int size = TYPE_IS_WIDE (t) ? 2 : 1;
+               if (target == IGNORE_TARGET)
+                 emit_pop (size, state);
+               else
+                 NOTE_PUSH (size);
+             }
            break;
          }
       }
       /* fall through */
+    notimpl:
     default:
-      error("internal error - tree code not implemented: ", TREE_CODE (exp));
+      error("internal error - tree code not implemented: %s",
+           tree_code_name [(int) TREE_CODE (exp)]);
     }
 }
 
+void
+perform_relocations (state)
+     struct jcf_partial *state;
+{
+  struct jcf_block *block;
+  struct jcf_relocation *reloc;
+  int pc;
+  int shrink;
+
+  /* Figure out the actual locations of each block. */
+  pc = 0;
+  shrink = 0;
+  for (block = state->blocks;  block != NULL;  block = block->next)
+    {
+      int block_size = block->chunk->size;
+
+      block->pc = pc;
+
+      /* Optimize GOTO L; L: by getting rid of the redundant goto.
+        Assumes relocations are in reverse order. */
+      reloc = block->u.relocations;
+      while (reloc != NULL
+            && reloc->label->pc == block->next->pc
+            && reloc->offset + 2 == block_size
+            && reloc->kind == OPCODE_goto_w)
+       {
+         reloc = reloc->next;
+         block->u.relocations = reloc;
+         block->chunk->size -= 3;
+         block_size -= 3;
+         shrink += 3;
+       }
+
+      for (reloc = block->u.relocations;  reloc != NULL;  reloc = reloc->next)
+       {
+         if (reloc->kind < -1 || reloc->kind > 0)
+           {
+             int delta = reloc->label->pc - (pc + reloc->offset - 1);
+             int expand = reloc->kind > 0 ? 2 : 5;
+
+             if (delta > 0)
+               delta -= shrink;
+             if (delta >= -32768 && delta <= 32767)
+               {
+                 shrink += expand;
+                 reloc->kind = -1;
+               }
+             else
+               block_size += expand;
+           }
+       }
+      pc += block_size;
+    }
+
+  for (block = state->blocks;  block != NULL;  block = block->next)
+    {
+      struct chunk *chunk = block->chunk;
+      int old_size = chunk->size;
+      int next_pc = block->next == NULL ? pc : block->next->pc;
+      int new_size = next_pc - block->pc;
+      int offset = 0;
+      unsigned char *new_ptr;
+      unsigned char *old_buffer = chunk->data;
+      unsigned char *old_ptr = old_buffer + old_size;
+      int new_end = new_size;
+      if (new_size != old_size)
+       {
+         chunk->data = (unsigned char *)
+           obstack_alloc (state->chunk_obstack, new_size);
+       }
+      new_ptr = chunk->data + new_size;
+
+      /* We do the relocations from back to front, because
+        thre relocations are in reverse order. */
+      for (reloc = block->u.relocations; ; reloc = reloc->next)
+       {
+         /* Lower old index of piece to be copied with no relocation. */
+         int start = reloc == NULL ? 0
+           : reloc->kind == 0 ? reloc->offset + 4
+           : reloc->offset + 2;
+         int32 value;
+         int new_offset;
+         int n = (old_ptr - old_buffer) - start;
+         new_ptr -= n;
+         old_ptr -= n;
+         if (n > 0)
+           bcopy (old_ptr, new_ptr, n);
+         if (old_ptr == old_buffer)
+           break;
+
+         if (reloc->kind == 0)
+           {
+             old_ptr -= 4;
+             value = GET_u4 (old_ptr);
+           }
+         else
+           {
+             old_ptr -= 2;
+             value = GET_u2 (old_ptr);
+           }
+         new_offset = new_ptr - chunk->data - (reloc->kind == -1 ? 2 : 4);
+         value += reloc->label->pc - (block->pc + new_offset);
+         *--new_ptr = (unsigned char) value;  value >>= 8;
+         *--new_ptr = (unsigned char) value;  value >>= 8;
+         if (reloc->kind != -1)
+           {
+             *--new_ptr = (unsigned char) value;  value >>= 8;
+             *--new_ptr = (unsigned char) value;
+           }
+         if (reloc->kind > 0)
+           {
+             /* Convert: OP TARGET to: OP_w TARGET;  (OP is goto or jsr). */
+             --old_ptr;
+             *--new_ptr = reloc->kind;
+           }
+         else if (reloc->kind < -1)
+           {
+             /* Convert: ifCOND TARGET to: ifNCOND T; goto_w TARGET; T: */
+             --old_ptr;
+             *--new_ptr = OPCODE_goto_w;
+             *--new_ptr = 3;
+             *--new_ptr = 0;
+             *--new_ptr = - reloc->kind;
+           }
+       }
+    }
+  state->code_length = pc;
+}
+
+void
+init_jcf_state (state, work)
+     struct jcf_partial *state;
+     struct obstack *work;
+{
+  state->chunk_obstack = work;
+  state->first = state->chunk = NULL;
+  CPOOL_INIT (&state->cpool);
+  BUFFER_INIT (&state->localvars);
+  BUFFER_INIT (&state->bytecode);
+}
+
+void
+init_jcf_method (state, method)
+     struct jcf_partial *state;
+     tree method;
+{
+  state->current_method = method;
+  state->blocks = state->last_block = NULL;
+  state->linenumber_count = 0;
+  state->first_lvar = state->last_lvar = NULL;
+  state->lvar_count = 0;
+  state->labeled_blocks = NULL;
+  state->code_length = 0;
+  BUFFER_RESET (&state->bytecode);
+  BUFFER_RESET (&state->localvars);
+  state->code_SP = 0;
+  state->code_SP_max = 0;
+}
+
+void
+release_jcf_state (state)
+     struct jcf_partial *state;
+{
+  CPOOL_FINISH (&state->cpool);
+  obstack_free (state->chunk_obstack, state->first);
+}
+
 /* 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. */
 
-/* Currently does not write any attributes i.e. no code. */
-
 struct chunk *
-generate_classfile (clas, work)
+generate_classfile (clas, state)
      tree clas;
-     struct obstack *work;
+     struct jcf_partial *state;
 {
-  CPool cpool;
-  struct chunk head;
-  struct chunk *chunk;
   struct chunk *cpool_chunk;
+  char *source_file;
   char *ptr;
   int i;
   char *fields_count_ptr;
   int fields_count = 0;
   char *methods_count_ptr;
   int methods_count = 0;
+  static tree SourceFile_node = NULL_TREE;
   tree part;
   int total_supers
     = clas == object_type_node ? 0
     : TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (clas));
-
-  chunk = alloc_chunk (&head, NULL, 8, work);
-  ptr = chunk->data;
+  
+  ptr = append_chunk (NULL, 8, state);
   PUT4 (0xCafeBabe);  /* Magic number */
   PUT2 (3);  /* Minor version */
   PUT2 (45);  /* Major version */
   
-  CPOOL_INIT(&cpool);
-  cpool_chunk = chunk = alloc_chunk (chunk, NULL, 0, work);
+  append_chunk (NULL, 0, state);
+  cpool_chunk = state->chunk;
 
   /* Next allocate the chunk containing acces_flags through fields_counr. */
   if (clas == object_type_node)
     i = 10;
   else
     i = 8 + 2 * total_supers;
-  chunk = alloc_chunk (chunk, NULL, i, work);
-  ptr = chunk->data;
+  ptr = append_chunk (NULL, i, state);
   i = get_access_flags (TYPE_NAME (clas));  PUT2 (i); /* acces_flags */
-  i = find_class_constant (&cpool, clas);  PUT2 (i);  /* this_class */
+  i = find_class_constant (&state->cpool, clas);  PUT2 (i);  /* this_class */
   if (clas == object_type_node)
     {
       PUT2(0);  /* super_class */
@@ -791,12 +1683,13 @@ generate_classfile (clas, work)
     {
       tree basetypes = TYPE_BINFO_BASETYPES (clas);
       tree base = BINFO_TYPE (TREE_VEC_ELT (basetypes, 0));
-      int j = find_class_constant (&cpool, base);  PUT2 (j);  /* super_class */
+      int j = find_class_constant (&state->cpool, base);
+      PUT2 (j);  /* super_class */
       PUT2 (total_supers - 1);  /* interfaces_count */
       for (i = 1;  i < total_supers;  i++)
        {
          base = BINFO_TYPE (TREE_VEC_ELT (basetypes, i));
-         j = find_class_constant (&cpool, base);
+         j = find_class_constant (&state->cpool, base);
          PUT2 (j);
        }
     }
@@ -806,11 +1699,10 @@ generate_classfile (clas, work)
     {
       if (DECL_NAME (part) == NULL_TREE)
        continue;
-      chunk = alloc_chunk (chunk, NULL, 8, work);
-      ptr = chunk->data;
+      ptr = append_chunk (NULL, 8, state);
       i = get_access_flags (part);  PUT2 (i);
-      i = find_utf8_constant (&cpool, DECL_NAME (part));  PUT2 (i);
-      i = find_utf8_constant (&cpool, build_java_signature (TREE_TYPE (part)));
+      i = find_utf8_constant (&state->cpool, DECL_NAME (part));  PUT2 (i);
+      i = find_utf8_constant (&state->cpool, build_java_signature (TREE_TYPE (part)));
       PUT2(i);
       PUT2 (0);  /* attributes_count */
       /* FIXME - emit ConstantValue attribute when appropriate */
@@ -818,120 +1710,141 @@ generate_classfile (clas, work)
     }
   ptr = fields_count_ptr;  PUT2 (fields_count);
 
-  chunk = alloc_chunk (chunk, NULL, 2, work);
-  ptr = methods_count_ptr = chunk->data;
+  ptr = methods_count_ptr = append_chunk (NULL, 2, state);
   PUT2 (0);
 
   for (part = TYPE_METHODS (clas);  part;  part = TREE_CHAIN (part))
     {
+      struct jcf_block *block;
       tree body = BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (part));
-      int linenumber_size;  /* 4 * number of line number entries */
-      chunk = alloc_chunk (chunk, NULL, 8, work);
-      ptr = chunk->data;
+      tree name = DECL_CONSTRUCTOR_P (part) ? init_identifier_node
+       : DECL_NAME (part);
+      tree type = TREE_TYPE (part);
+      ptr = append_chunk (NULL, 8, state);
       i = get_access_flags (part);  PUT2 (i);
-      i = find_utf8_constant (&cpool, DECL_NAME (part));  PUT2 (i);
-      i = find_utf8_constant (&cpool, build_java_signature (TREE_TYPE (part)));
+      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 */
       if (body != NULL_TREE)
        {
          int code_attributes_count = 0;
-         int linenumber_size;  /* 4 * number of line number entries */
-         int localvartable_size;  /* 10 * number of local variable entries */
          static tree Code_node = NULL_TREE;
          tree t;
          char *attr_len_ptr;
-         int code_length;
          if (Code_node == NULL_TREE)
            Code_node = get_identifier ("Code");
-         chunk = alloc_chunk (chunk, NULL, 14, work);
-         ptr = chunk->data;
-         i = find_utf8_constant (&cpool, Code_node);  PUT2 (i);
+         ptr = append_chunk (NULL, 14, state);
+         i = find_utf8_constant (&state->cpool, Code_node);  PUT2 (i);
          attr_len_ptr = ptr;
-         BUFFER_RESET (&bytecode);
-         BUFFER_RESET (&localvartable);
-         BUFFER_RESET (&linenumbers);
-         BUFFER_RESET (&localvars);
-         code_SP = 0;
-         code_SP_max = 0;
-         code_cpool = &cpool;
+         init_jcf_method (state, part);
+         get_jcf_label_here (state);  /* Force a first block. */
          for (t = DECL_ARGUMENTS (part);  t != NULL_TREE;  t = TREE_CHAIN (t))
-           localvar_alloc (t, 0);
-         generate_bytecode_insns (part, body, IGNORE_TARGET);
-         code_length = PC;     
+           localvar_alloc (t, state);
+         generate_bytecode_insns (body, IGNORE_TARGET, state);
          for (t = DECL_ARGUMENTS (part);  t != NULL_TREE;  t = TREE_CHAIN (t))
-           localvar_free (t, code_length);
-         linenumber_size = BUFFER_LENGTH (&linenumbers);
-         localvartable_size = BUFFER_LENGTH (&localvartable);
-         chunk = alloc_chunk (chunk, NULL, code_length, work);
-         bcopy (bytecode.data, chunk->data, code_length);
+           localvar_free (t, state);
+         finish_jcf_block (state);
+         perform_relocations (state);
+
          ptr = attr_len_ptr;
-         i = 8 + code_length + 4;
-         if (linenumber_size > 0)
+         i = 8 + state->code_length + 4;
+         if (state->linenumber_count > 0)
            {
              code_attributes_count++;
-             i += 8 + linenumber_size;
+             i += 8 + 4 * state->linenumber_count;
            }
-         if (localvartable_size > 0)
+         if (state->lvar_count > 0)
            {
              code_attributes_count++;
-             i += 8 + localvartable_size;
+             i += 8 + 10 * state->lvar_count;
            }
          PUT4 (i); /* attribute_length */
-         PUT2 (code_SP_max);  /* max_stack */
+         PUT2 (state->code_SP_max);  /* max_stack */
          PUT2 (localvar_max);  /* max_locals */
-         PUT4 (code_length);
-         chunk = alloc_chunk (chunk, NULL, 4, work);
-         ptr = chunk->data;
+         PUT4 (state->code_length);
+         ptr = append_chunk (NULL, 4, state);
          PUT2 (0);  /* exception_table_length */
          PUT2 (code_attributes_count);
 
          /* Write the LineNumberTable attribute. */
-         if (linenumber_size > 0)
+         if (state->linenumber_count > 0)
            {
              static tree LineNumberTable_node = NULL_TREE;
-             chunk = alloc_chunk (chunk, NULL, 8 + linenumber_size, work);
-             ptr = chunk->data;
+             ptr = append_chunk (NULL, 8 + 4 * state->linenumber_count, state);
              if (LineNumberTable_node == NULL_TREE)
                LineNumberTable_node = get_identifier ("LineNumberTable");
-             i = find_utf8_constant (&cpool, LineNumberTable_node);
+             i = find_utf8_constant (&state->cpool, LineNumberTable_node);
              PUT2 (i);  /* attribute_name_index */
-             i = 2 + linenumber_size;  PUT4 (i);  /* attribute_length */
-             i = linenumber_size >> 2;  PUT2 (i);
-             PUTN (linenumbers.data, linenumber_size);
+             i = 2+4*state->linenumber_count;  PUT4(i); /* attribute_length */
+             i = state->linenumber_count;  PUT2 (i);
+             for (block = state->blocks;  block != NULL;  block = block->next)
+               {
+                 int line = block->linenumber;
+                 if (line > 0)
+                   {
+                     PUT2 (block->pc);
+                     PUT2 (line);
+                   }
+               }
            }
 
          /* Write the LocalVariableTable attribute. */
-         if (localvartable_size > 0)
+         if (state->lvar_count > 0)
            {
              static tree LocalVariableTable_node = NULL_TREE;
-             chunk = alloc_chunk (chunk, NULL, 8 + localvartable_size, work);
-             ptr = chunk->data;
+             struct localvar_info *lvar = state->first_lvar;
+             ptr = append_chunk (NULL, 8 + 10 * state->lvar_count, state);
              if (LocalVariableTable_node == NULL_TREE)
                LocalVariableTable_node = get_identifier("LocalVariableTable");
-             i = find_utf8_constant (&cpool, LocalVariableTable_node);
+             i = find_utf8_constant (&state->cpool, LocalVariableTable_node);
              PUT2 (i);  /* attribute_name_index */
-             i = 2 + localvartable_size;  PUT4 (i);  /* attribute_length */
-             i = localvartable_size / 10;  PUT2 (i);
-             PUTN (localvartable.data, localvartable_size);
+             i = 2 + 10 * state->lvar_count;  PUT4 (i); /* attribute_length */
+             i = state->lvar_count;  PUT2 (i);
+             for ( ; lvar != NULL;  lvar = lvar->next)
+               {
+                 tree name = DECL_NAME (lvar->decl);
+                 tree sig = build_java_signature (TREE_TYPE (lvar->decl));
+                 i = lvar->start_label->pc;  PUT2 (i);
+                 i = lvar->end_label->pc - i;  PUT2 (i);
+                 i = find_utf8_constant (&state->cpool, name);  PUT2 (i);
+                 i = find_utf8_constant (&state->cpool, sig);  PUT2 (i);
+                 i = DECL_LOCAL_INDEX (lvar->decl);  PUT2 (i);
+               }
            }
        }
       methods_count++;
     }
   ptr = methods_count_ptr;  PUT2 (methods_count);
 
-  chunk = alloc_chunk (chunk, NULL, 2, work);
-  ptr = chunk->data;
-  PUT2 (0);  /* attributes_count */
+  source_file = DECL_SOURCE_FILE (TYPE_NAME (clas));
+  for (ptr = source_file;  ;  ptr++)
+    {
+      char ch = *ptr;
+      if (ch == '\0')
+       break;
+      if (ch == '/' || ch == '\\')
+       source_file = ptr+1;
+    }
+  ptr = append_chunk (NULL, 10, state);
+  PUT2 (1);  /* attributes_count */
+
+  /* generate the SourceFile attribute. */
+  if (SourceFile_node == NULL_TREE) 
+    SourceFile_node = get_identifier ("SourceFile");
+  i = find_utf8_constant (&state->cpool, SourceFile_node);
+  PUT2 (i);  /* attribute_name_index */
+  PUT4 (2);
+  i = find_utf8_constant (&state->cpool, get_identifier (source_file));
+  PUT2 (i);
 
   /* New finally generate the contents of the constant pool chunk. */
-  i = count_constant_pool_bytes (&cpool);
-  ptr = obstack_alloc (work, i);
+  i = count_constant_pool_bytes (&state->cpool);
+  ptr = obstack_alloc (state->chunk_obstack, i);
   cpool_chunk->data = ptr;
   cpool_chunk->size = i;
-  write_constant_pool (&cpool, ptr, i);
-  CPOOL_FINISH (&cpool);
-  return head.next;
+  write_constant_pool (&state->cpool, ptr, i);
+  return state->first;
 }
 
 char*
@@ -951,14 +1864,16 @@ write_classfile (clas)
      tree clas;
 {
   struct obstack *work = &temporary_obstack;
+  struct jcf_partial state[1];
   char *class_file_name = make_class_file_name (clas);
   struct chunk *chunks;
   FILE* stream = fopen (class_file_name, "wb");
   if (stream == NULL)
     fatal ("failed to open `%s' for writing", class_file_name);
-  chunks = generate_classfile (clas, work);
+  init_jcf_state (state, work);
+  chunks = generate_classfile (clas, state);
   write_chunks (stream, chunks);
   if (fclose (stream))
     fatal ("failed to close after writing `%s'", class_file_name);
-  obstack_free (work, chunks);
+  release_jcf_state (state);
 }
index 7d46f50..21c30c1 100644 (file)
@@ -32,6 +32,40 @@ The Free Software Foundation is independent of Sun Microsystems, Inc.  */
 #include "jcf.h"
 #include "toplev.h"
 
+/* Table indexed by tree code giving a string containing a character
+   classifying the tree code.  Possibilities are
+   t, d, s, c, r, <, 1 and 2.  See java/java-tree.def for details.  */
+
+#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,
+
+char java_tree_code_type[] = {
+  'x',
+#include "java-tree.def"
+};
+#undef DEFTREECODE
+
+/* Table indexed by tree code giving number of expression
+   operands beyond the fixed part of the node structure.
+   Not used for types or decls.  */
+
+#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH,
+
+int java_tree_code_length[] = {
+  0,
+#include "java-tree.def"
+};
+#undef DEFTREECODE
+
+/* Names of tree components.
+   Used for printing out the tree and error messages.  */
+#define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME,
+
+char *java_tree_code_name[] = {
+  "@@dummy",
+#include "java-tree.def"
+};
+#undef DEFTREECODE
+
 int compiling_from_source;
 
 char *language_string = "GNU Java";
@@ -320,6 +354,20 @@ lang_init ()
   current_jcf = main_jcf;
 
   flag_exceptions = 1;
+
+  /* Append to Gcc tree node definition arrays */
+
+  bcopy (java_tree_code_type,
+        tree_code_type + (int) LAST_AND_UNUSED_TREE_CODE,
+        (int)LAST_JAVA_TREE_CODE - (int)LAST_AND_UNUSED_TREE_CODE);
+  bcopy ((char *)java_tree_code_length,
+        (char *)(tree_code_length + (int) LAST_AND_UNUSED_TREE_CODE),
+        (LAST_JAVA_TREE_CODE - 
+         (int)LAST_AND_UNUSED_TREE_CODE) * sizeof (int));
+  bcopy ((char *)java_tree_code_name,
+        (char *)(tree_code_name + (int) LAST_AND_UNUSED_TREE_CODE),
+        (LAST_JAVA_TREE_CODE - 
+         (int)LAST_AND_UNUSED_TREE_CODE) * sizeof (char *));
 }
 
 /* This doesn't do anything on purpose. It's used to satisfy the
index 50d5140..1e78e32 100644 (file)
@@ -148,22 +148,32 @@ extern tree stabilize_reference PROTO ((tree));
     EXPR_WFL_EMIT_LINE_NOTE (node) = 1, node : node)
 
 /* Types classification, according to the JLS, section 4.2 */
-#define JFLOAT_TYPE_P(TYPE)      (TREE_CODE ((TYPE)) == REAL_TYPE)
-#define JINTEGRAL_TYPE_P(TYPE)   ((TREE_CODE ((TYPE)) == INTEGER_TYPE) \
-                                 || (TREE_CODE ((TYPE)) == CHAR_TYPE))
-#define JNUMERIC_TYPE_P(TYPE)    (JFLOAT_TYPE_P ((TYPE))       \
-                                 || JINTEGRAL_TYPE_P ((TYPE)))
-#define JPRIMITIVE_TYPE_P(TYPE)  (JNUMERIC_TYPE_P ((TYPE))                \
-                                 || (TREE_CODE ((TYPE)) == BOOLEAN_TYPE))
+#define JFLOAT_TYPE_P(TYPE)      (TYPE && TREE_CODE ((TYPE)) == REAL_TYPE)
+#define JINTEGRAL_TYPE_P(TYPE)   ((TYPE)                                  \
+                                 && (TREE_CODE ((TYPE)) == INTEGER_TYPE   \
+                                     || TREE_CODE ((TYPE)) == CHAR_TYPE))
+#define JNUMERIC_TYPE_P(TYPE)    ((TYPE)                               \
+                                 && (JFLOAT_TYPE_P ((TYPE))            \
+                                     || JINTEGRAL_TYPE_P ((TYPE))))
+#define JPRIMITIVE_TYPE_P(TYPE)  ((TYPE)                                 \
+                                 && (JNUMERIC_TYPE_P ((TYPE))            \
+                                 || TREE_CODE ((TYPE)) == BOOLEAN_TYPE))
 
 /* Not defined in the LRM */
-#define JSTRING_TYPE_P(TYPE) ((TYPE) == string_type_node ||            \
-                        (TREE_CODE (TYPE) == POINTER_TYPE &&           \
-                         TREE_TYPE (op1_type) == string_type_node))
-
-#define JREFERENCE_TYPE_P(TYPE) (TREE_CODE (TYPE) == RECORD_TYPE ||    \
-                                (TREE_CODE (TYPE) == POINTER_TYPE &&   \
-                                TREE_CODE (TREE_TYPE (TYPE)) == RECORD_TYPE))
+#define JSTRING_TYPE_P(TYPE) ((TYPE)                                      \
+                             && ((TYPE) == string_type_node ||            \
+                                 (TREE_CODE (TYPE) == POINTER_TYPE &&     \
+                                  TREE_TYPE (TYPE) == string_type_node)))
+#define JSTRING_P(NODE) ((NODE)                                                \
+                        && (TREE_CODE (NODE) == STRING_CST             \
+                            || IS_CRAFTED_STRING_BUFFER_P (NODE)       \
+                            || JSTRING_TYPE_P (TREE_TYPE (NODE))))
+
+#define JREFERENCE_TYPE_P(TYPE) ((TYPE)                                              \
+                                && (TREE_CODE (TYPE) == RECORD_TYPE          \
+                                    || (TREE_CODE (TYPE) == POINTER_TYPE     \
+                                        &&  TREE_CODE (TREE_TYPE (TYPE)) ==  \
+                                        RECORD_TYPE)))
 
 /* Other predicate */
 #define DECL_P(NODE) (NODE && (TREE_CODE (NODE) == PARM_DECL           \
@@ -198,12 +208,12 @@ extern tree stabilize_reference PROTO ((tree));
 
 #define ERROR_VARIABLE_NOT_INITIALIZED(WFL, V)                 \
   parse_error_context                                          \
-    ((WFL), "Variable `%s' may not have been initialized",     \
+    ((WFL), "Variable `%s' may not have been initialized",     \
      IDENTIFIER_POINTER (V))
 
-/* Definition for loop handling. This Java's own definition of a loop
-   body. See parse.y for documentation. It's valid once you hold a
-   loop's body (LOOP_EXPR_BODY) */
+/* Definition for loop handling. This is Java's own definition of a
+   loop body. See parse.y for documentation. It's valid once you hold
+   loop's body (LOOP_EXPR_BODY) */
 
 /* The loop main block is the one hold the condition and the loop body */
 #define LOOP_EXPR_BODY_MAIN_BLOCK(NODE) TREE_OPERAND (NODE, 0)
@@ -252,7 +262,6 @@ extern tree stabilize_reference PROTO ((tree));
   }
 #define POP_LOOP() ctxp->current_loop = TREE_CHAIN (ctxp->current_loop)
 
-
 /* Invocation modes, as returned by invocation_mode (). */
 enum {
   INVOKE_STATIC,
@@ -414,6 +423,14 @@ static jdeplist *reverse_jdep_list ();
 #define COMPLETE_CHECK_OP_0(NODE) COMPLETE_CHECK_OP(NODE, 0)
 #define COMPLETE_CHECK_OP_1(NODE) COMPLETE_CHECK_OP(NODE, 1)
 
+/* Building invocations: append(ARG) and StringBuffer(ARG) */
+#define BUILD_APPEND(ARG)                                                   \
+  build_method_invocation (wfl_append,                                              \
+                          (ARG ? build_tree_list (NULL, (ARG)): NULL_TREE))
+#define BUILD_STRING_BUFFER(ARG)                                             \
+  build_new_invocation (wfl_string_buffer,                                   \
+                       (ARG ? build_tree_list (NULL, (ARG)) : NULL_TREE))
+
 /* Parser context data structure. */
 struct parser_ctxt {
 
@@ -472,7 +489,8 @@ struct parser_ctxt {
 #ifndef JC1_LITE
 static char *java_accstring_lookup PROTO ((int));
 static void  parse_error PROTO ((char *));
-static void  redefinition_error PROTO ((char *,tree, tree, tree));
+static void  classitf_redefinition_error PROTO ((char *,tree, tree, tree));
+static void  variable_redefinition_error PROTO ((tree, tree, tree, int));
 static void  check_modifiers PROTO ((char *, int, int));
 static tree  create_class PROTO ((int, tree, tree, tree));
 static tree  create_interface PROTO ((int, tree, tree));
@@ -490,6 +508,7 @@ static tree method_header PROTO ((int, tree, tree, tree));
 static tree method_declarator PROTO ((tree, tree));
 static void parse_error_context VPROTO ((tree cl, char *msg, ...));
 static void parse_warning_context VPROTO ((tree cl, char *msg, ...));
+static tree parse_jdk1_1_error PROTO ((char *));
 static void complete_class_report_errors PROTO ((jdep *));
 static int process_imports PROTO ((void));
 static void read_import_dir PROTO ((tree));
@@ -514,7 +533,9 @@ static tree resolve_and_layout PROTO ((tree, tree));
 static tree resolve_no_layout PROTO ((tree, tree));
 static int identical_subpath_p PROTO ((tree, tree));
 static int invocation_mode PROTO ((tree, int));
-static tree refine_accessible_methods_list PROTO ((int, tree));
+static tree find_applicable_accessible_methods_list PROTO ((tree, tree, tree));
+static tree find_most_specific_methods_list PROTO ((tree));
+static int argument_types_convertible PROTO ((tree, tree));
 static tree patch_invoke PROTO ((tree, tree, tree, tree));
 static tree lookup_method_invoke PROTO ((int, tree, tree, tree, tree));
 static tree register_incomplete_type PROTO ((int, tree, tree, tree));
@@ -525,10 +546,12 @@ static int  unresolved_type_p PROTO ((tree, tree *));
 static void create_jdep_list PROTO ((struct parser_ctxt *));
 static tree build_expr_block PROTO ((tree, tree));
 static tree enter_block PROTO ((void));
+static tree enter_a_block PROTO ((tree));
 static tree exit_block PROTO ((void));
 static tree lookup_name_in_blocks PROTO ((tree));
 static void maybe_absorb_scoping_blocks PROTO ((void));
 static tree build_method_invocation PROTO ((tree, tree));
+static tree build_new_invocation PROTO ((tree, tree));
 static tree build_assignment PROTO ((int, int, tree, tree));
 static tree build_binop PROTO ((enum tree_code, int, tree, tree));
 static tree patch_assignment PROTO ((tree, tree, tree ));
@@ -539,7 +562,11 @@ static tree patch_unaryop PROTO ((tree, tree));
 static tree build_cast PROTO ((int, tree, tree));
 static tree patch_cast PROTO ((tree, tree, tree));
 static int valid_ref_assignconv_cast_p PROTO ((tree, tree, int));
-static int can_cast_to_p PROTO ((tree, tree));
+static int valid_builtin_assignconv_identity_widening_p PROTO ((tree, tree));
+static int valid_cast_to_p PROTO ((tree, tree));
+static int valid_method_invocation_conversion_p PROTO ((tree, tree));
+static tree try_builtin_assignconv PROTO ((tree, tree, tree));
+static tree try_reference_assignconv PROTO ((tree, tree));
 static tree build_unresolved_array_type PROTO ((tree));
 static tree build_array_ref PROTO ((int, tree, tree));
 static tree patch_array_ref PROTO ((tree, tree, tree));
@@ -565,6 +592,7 @@ static int class_in_current_package PROTO ((tree));
 static tree build_if_else_statement PROTO ((int, tree, tree, tree));
 static tree patch_if_else_statement PROTO ((tree));
 static tree add_stmt_to_compound PROTO ((tree, tree, tree));
+static tree add_stmt_to_block PROTO ((tree, tree, tree));
 static tree patch_exit_expr PROTO ((tree));
 static tree build_labeled_block PROTO ((int, tree, tree));
 static tree generate_labeled_block PROTO (());
@@ -577,6 +605,14 @@ static tree build_loop_body PROTO ((int, tree, int));
 static tree complete_loop_body PROTO ((int, tree, tree, int));
 static tree build_debugable_stmt PROTO ((int, tree));
 static tree complete_for_loop PROTO ((int, tree, tree, tree));
+static tree patch_switch_statement PROTO ((tree));
+static tree string_constant_concatenation PROTO ((tree, tree));
+static tree build_string_concatenation PROTO ((tree, tree));
+static tree patch_string_cst PROTO ((tree));
+static tree patch_string PROTO ((tree));
+static tree build_jump_to_finally PROTO ((tree, tree, tree, tree));
+static tree build_try_statement PROTO ((int, tree, tree, tree));
+static tree patch_try_statement PROTO ((tree));
 
 void safe_layout_class PROTO ((tree));
 void java_complete_class PROTO ((void));
@@ -586,6 +622,8 @@ void java_check_methods PROTO ((void));
 void java_layout_classes PROTO ((void));
 tree java_method_add_stmt PROTO ((tree, tree));
 char *java_get_line_col PROTO ((char *, int, int));
+void java_expand_switch PROTO ((tree));
+tree java_get_catch_block PROTO ((tree, int));
 #endif /* JC1_LITE */
 
 /* Always in use, no matter what you compile */
index e0d4e09..d73c52a 100644 (file)
@@ -930,14 +930,14 @@ verify_jvm_instructions (jcf, byte_ops, length)
        case OPCODE_instanceof:
          pop_type (ptr_type_node);
          get_class_constant (current_jcf, IMMEDIATE_u2);
-         push_type (integer_type_node);
+         push_type (int_type_node);
          break;
 
        case OPCODE_tableswitch:
          {
            jint default_val, low, high;
 
-           pop_type (integer_type_node);
+           pop_type (int_type_node);
            while (PC%4)
              {
                if (byte_ops[PC++])
@@ -959,7 +959,7 @@ verify_jvm_instructions (jcf, byte_ops, length)
          {
            jint npairs, last, not_registered = 1;
 
-           pop_type (integer_type_node);
+           pop_type (int_type_node);
            while (PC%4)
              {
                if (byte_ops[PC++])