aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPer Bothner <bothner@cygnus.com>1998-10-12 12:43:53 +0000
committerPer Bothner <bothner@cygnus.com>1998-10-12 12:43:53 +0000
commit2ea6d31e8f83da16e2242971dde5f7fd64c5ad5a (patch)
tree6b8fd99c924c31f0820d242808644e6ac851276e
parentd570e134a672fe0ff0545725107c97b560624208 (diff)
Merge from Cygnus internal source tree. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@23025 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/java/Makefile.in16
-rw-r--r--gcc/java/buffer.h3
-rw-r--r--gcc/java/except.c52
-rw-r--r--gcc/java/expr.c142
-rw-r--r--gcc/java/gjavah.c381
-rw-r--r--gcc/java/jcf-parse.c2
-rw-r--r--gcc/java/jcf-write.c1541
-rw-r--r--gcc/java/lang.c48
-rw-r--r--gcc/java/parse.h82
-rw-r--r--gcc/java/verify.c6
10 files changed, 1749 insertions, 524 deletions
diff --git a/gcc/java/Makefile.in b/gcc/java/Makefile.in
index efe7ef1bf00..d7e009d4a49 100644
--- a/gcc/java/Makefile.in
+++ b/gcc/java/Makefile.in
@@ -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:
diff --git a/gcc/java/buffer.h b/gcc/java/buffer.h
index aa63840d759..924f6e0f276 100644
--- a/gcc/java/buffer.h
+++ b/gcc/java/buffer.h
@@ -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)
diff --git a/gcc/java/except.c b/gcc/java/except.c
index cbfeb0a8cc2..caa2a313c64 100644
--- a/gcc/java/except.c
+++ b/gcc/java/except.c
@@ -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 ();
diff --git a/gcc/java/expr.c b/gcc/java/expr.c
index 3b8538c60e8..8322d616315 100644
--- a/gcc/java/expr.c
+++ b/gcc/java/expr.c
@@ -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) \
diff --git a/gcc/java/gjavah.c b/gcc/java/gjavah.c
index fd39df6b8fc..b6229cc3a77 100644
--- a/gcc/java/gjavah.c
+++ b/gcc/java/gjavah.c
@@ -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. */
diff --git a/gcc/java/jcf-parse.c b/gcc/java/jcf-parse.c
index cdcbcedd8e1..e6b8ba1be48 100644
--- a/gcc/java/jcf-parse.c
+++ b/gcc/java/jcf-parse.c
@@ -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);
diff --git a/gcc/java/jcf-write.c b/gcc/java/jcf-write.c
index af663017bfd..deda8c1f600 100644
--- a/gcc/java/jcf-write.c
+++ b/gcc/java/jcf-write.c
@@ -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))
-/* 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);
+}
+
+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++;
}
+
/* 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;
}
-
}
#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);
}
diff --git a/gcc/java/lang.c b/gcc/java/lang.c
index 7d46f50eb5d..21c30c131f1 100644
--- a/gcc/java/lang.c
+++ b/gcc/java/lang.c
@@ -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
diff --git a/gcc/java/parse.h b/gcc/java/parse.h
index 50d51401149..1e78e328ab8 100644
--- a/gcc/java/parse.h
+++ b/gcc/java/parse.h
@@ -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
+ a 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 */
diff --git a/gcc/java/verify.c b/gcc/java/verify.c
index e0d4e097773..d73c52af6a6 100644
--- a/gcc/java/verify.c
+++ b/gcc/java/verify.c
@@ -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++])