X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fjava%2Fjcf-write.c;h=aed6eb9773b7ee3b79e517b648322768b26474db;hb=8d64cb2d4aa6dd77829e3ba5b529e26ed0b7d287;hp=f9c4679b36dda9dc3e004e30e70991be1b10c328;hpb=7d82ed5e37525c7a0f118b54ad036fde37651800;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/java/jcf-write.c b/gcc/java/jcf-write.c index f9c4679b36d..aed6eb9773b 100644 --- a/gcc/java/jcf-write.c +++ b/gcc/java/jcf-write.c @@ -31,7 +31,6 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */ #include "real.h" #include "java-tree.h" #include "obstack.h" -#undef AND #include "rtl.h" #include "flags.h" #include "java-opcodes.h" @@ -39,17 +38,14 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */ #include "buffer.h" #include "toplev.h" #include "ggc.h" - -#ifndef DIR_SEPARATOR -#define DIR_SEPARATOR '/' -#endif +#include "tm_p.h" extern struct obstack temporary_obstack; /* Base directory in which `.class' files should be written. NULL means to put the file into the same directory as the corresponding .java file. */ -char *jcf_write_base_directory = NULL; +const char *jcf_write_base_directory = NULL; /* Make sure bytecode.data is big enough for at least N more bytes. */ @@ -129,7 +125,7 @@ struct jcf_block If the label has been defined: Until perform_relocations is finished, this is the maximum possible - value of the bytecode offset at the begnning of this block. + value of the bytecode offset at the beginning of this block. After perform_relocations, it is the actual offset (pc). */ int pc; @@ -279,89 +275,85 @@ struct jcf_partial /* Information about the current switch statement. */ struct jcf_switch_state *sw_state; + + /* The count of jsr instructions that have been emmitted. */ + long num_jsrs; }; -static void generate_bytecode_insns PARAMS ((tree, int, struct jcf_partial *)); -static struct chunk * alloc_chunk PARAMS ((struct chunk *, unsigned char *, - int, struct obstack *)); -static unsigned char * append_chunk PARAMS ((unsigned char *, int, - struct jcf_partial *)); -static void append_chunk_copy PARAMS ((unsigned char *, int, - struct jcf_partial *)); -static struct jcf_block * gen_jcf_label PARAMS ((struct jcf_partial *)); -static void finish_jcf_block PARAMS ((struct jcf_partial *)); -static void define_jcf_label PARAMS ((struct jcf_block *, - struct jcf_partial *)); -static struct jcf_block * get_jcf_label_here PARAMS ((struct jcf_partial *)); -static void put_linenumber PARAMS ((int, struct jcf_partial *)); -static void localvar_alloc PARAMS ((tree, struct jcf_partial *)); -static void localvar_free PARAMS ((tree, struct jcf_partial *)); -static int get_access_flags PARAMS ((tree)); -static void write_chunks PARAMS ((FILE *, struct chunk *)); -static int adjust_typed_op PARAMS ((tree, int)); -static void generate_bytecode_conditional PARAMS ((tree, struct jcf_block *, - struct jcf_block *, int, - struct jcf_partial *)); -static void generate_bytecode_return PARAMS ((tree, struct jcf_partial *)); -static void perform_relocations PARAMS ((struct jcf_partial *)); -static void init_jcf_state PARAMS ((struct jcf_partial *, struct obstack *)); -static void init_jcf_method PARAMS ((struct jcf_partial *, tree)); -static void release_jcf_state PARAMS ((struct jcf_partial *)); -static struct chunk * generate_classfile PARAMS ((tree, struct jcf_partial *)); -static struct jcf_handler *alloc_handler PARAMS ((struct jcf_block *, - struct jcf_block *, - struct jcf_partial *)); -static void emit_iinc PARAMS ((tree, HOST_WIDE_INT, struct jcf_partial *)); -static void emit_reloc PARAMS ((HOST_WIDE_INT, int, struct jcf_block *, - struct jcf_partial *)); -static void push_constant1 PARAMS ((HOST_WIDE_INT, struct jcf_partial *)); -static void push_constant2 PARAMS ((HOST_WIDE_INT, struct jcf_partial *)); -static void push_int_const PARAMS ((HOST_WIDE_INT, struct jcf_partial *)); -static int find_constant_wide PARAMS ((HOST_WIDE_INT, HOST_WIDE_INT, - struct jcf_partial *)); -static void push_long_const PARAMS ((HOST_WIDE_INT, HOST_WIDE_INT, - struct jcf_partial *)); -static int find_constant_index PARAMS ((tree, struct jcf_partial *)); -static void push_long_const PARAMS ((HOST_WIDE_INT, HOST_WIDE_INT, - struct jcf_partial *)); -static void field_op PARAMS ((tree, int, struct jcf_partial *)); -static void maybe_wide PARAMS ((int, int, struct jcf_partial *)); -static void emit_dup PARAMS ((int, int, struct jcf_partial *)); -static void emit_pop PARAMS ((int, struct jcf_partial *)); -static void emit_load_or_store PARAMS ((tree, int, struct jcf_partial *)); -static void emit_load PARAMS ((tree, struct jcf_partial *)); -static void emit_store PARAMS ((tree, struct jcf_partial *)); -static void emit_unop PARAMS ((enum java_opcode, tree, struct jcf_partial *)); -static void emit_binop PARAMS ((enum java_opcode, tree, struct jcf_partial *)); -static void emit_reloc PARAMS ((HOST_WIDE_INT, int, struct jcf_block *, - struct jcf_partial *)); -static void emit_switch_reloc PARAMS ((struct jcf_block *, - struct jcf_partial *)); -static void emit_case_reloc PARAMS ((struct jcf_relocation *, - struct jcf_partial *)); -static void emit_if PARAMS ((struct jcf_block *, int, int, - struct jcf_partial *)); -static void emit_goto PARAMS ((struct jcf_block *, struct jcf_partial *)); -static void emit_jsr PARAMS ((struct jcf_block *, struct jcf_partial *)); -static void call_cleanups PARAMS ((struct jcf_block *, struct jcf_partial *)); -static char *make_class_file_name PARAMS ((tree)); -static unsigned char *append_synthetic_attribute PARAMS ((struct jcf_partial *)); -static void append_innerclasses_attribute PARAMS ((struct jcf_partial *, tree)); -static void append_innerclasses_attribute_entry PARAMS ((struct jcf_partial *, tree, tree)); -static void append_gcj_attribute PARAMS ((struct jcf_partial *, tree)); +static void generate_bytecode_insns (tree, int, struct jcf_partial *); +static struct chunk * alloc_chunk (struct chunk *, unsigned char *, + int, struct obstack *); +static unsigned char * append_chunk (unsigned char *, int, + struct jcf_partial *); +static void append_chunk_copy (unsigned char *, int, struct jcf_partial *); +static struct jcf_block * gen_jcf_label (struct jcf_partial *); +static void finish_jcf_block (struct jcf_partial *); +static void define_jcf_label (struct jcf_block *, struct jcf_partial *); +static struct jcf_block * get_jcf_label_here (struct jcf_partial *); +static void put_linenumber (int, struct jcf_partial *); +static void localvar_alloc (tree, struct jcf_partial *); +static void maybe_free_localvar (tree, struct jcf_partial *, int); +static int get_access_flags (tree); +static void write_chunks (FILE *, struct chunk *); +static int adjust_typed_op (tree, int); +static void generate_bytecode_conditional (tree, struct jcf_block *, + struct jcf_block *, int, + struct jcf_partial *); +static void generate_bytecode_return (tree, struct jcf_partial *); +static void perform_relocations (struct jcf_partial *); +static void init_jcf_state (struct jcf_partial *, struct obstack *); +static void init_jcf_method (struct jcf_partial *, tree); +static void release_jcf_state (struct jcf_partial *); +static struct chunk * generate_classfile (tree, struct jcf_partial *); +static struct jcf_handler *alloc_handler (struct jcf_block *, + struct jcf_block *, + struct jcf_partial *); +static void emit_iinc (tree, HOST_WIDE_INT, struct jcf_partial *); +static void emit_reloc (HOST_WIDE_INT, int, struct jcf_block *, + struct jcf_partial *); +static void push_constant1 (HOST_WIDE_INT, struct jcf_partial *); +static void push_constant2 (HOST_WIDE_INT, struct jcf_partial *); +static void push_int_const (HOST_WIDE_INT, struct jcf_partial *); +static int find_constant_wide (HOST_WIDE_INT, HOST_WIDE_INT, + struct jcf_partial *); +static void push_long_const (HOST_WIDE_INT, HOST_WIDE_INT, + struct jcf_partial *); +static int find_constant_index (tree, struct jcf_partial *); +static void push_long_const (HOST_WIDE_INT, HOST_WIDE_INT, + struct jcf_partial *); +static void field_op (tree, int, struct jcf_partial *); +static void maybe_wide (int, int, struct jcf_partial *); +static void emit_dup (int, int, struct jcf_partial *); +static void emit_pop (int, struct jcf_partial *); +static void emit_load_or_store (tree, int, struct jcf_partial *); +static void emit_load (tree, struct jcf_partial *); +static void emit_store (tree, struct jcf_partial *); +static void emit_unop (enum java_opcode, tree, struct jcf_partial *); +static void emit_binop (enum java_opcode, tree, struct jcf_partial *); +static void emit_reloc (HOST_WIDE_INT, int, struct jcf_block *, + struct jcf_partial *); +static void emit_switch_reloc (struct jcf_block *, struct jcf_partial *); +static void emit_case_reloc (struct jcf_relocation *, struct jcf_partial *); +static void emit_if (struct jcf_block *, int, int, struct jcf_partial *); +static void emit_goto (struct jcf_block *, struct jcf_partial *); +static void emit_jsr (struct jcf_block *, struct jcf_partial *); +static void call_cleanups (struct jcf_block *, struct jcf_partial *); +static char *make_class_file_name (tree); +static unsigned char *append_synthetic_attribute (struct jcf_partial *); +static void append_deprecated_attribute (struct jcf_partial *); +static void append_innerclasses_attribute (struct jcf_partial *, tree); +static void append_innerclasses_attribute_entry (struct jcf_partial *, tree, tree); +static void append_gcj_attribute (struct jcf_partial *, tree); /* 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 enough space has been allocated. */ #ifdef ENABLE_JC1_CHECKING -static int CHECK_PUT PARAMS ((void *, struct jcf_partial *, int)); +static int CHECK_PUT (void *, struct jcf_partial *, int); static int -CHECK_PUT (ptr, state, i) - void *ptr; - struct jcf_partial *state; - int i; +CHECK_PUT (void *ptr, struct jcf_partial *state, int i) { if ((unsigned char *) ptr < state->chunk->data || (unsigned char *) ptr + i > state->chunk->data + state->chunk->size) @@ -391,14 +383,10 @@ CHECK_PUT (ptr, state, i) However, if DATA is NULL and SIZE>0, allocate a buffer as well. */ static struct chunk * -alloc_chunk (last, data, size, work) - struct chunk *last; - unsigned char *data; - int size; - struct obstack *work; +alloc_chunk (struct chunk *last, unsigned char *data, + int size, struct obstack *work) { - struct chunk *chunk = (struct chunk *) - obstack_alloc (work, sizeof(struct chunk)); + struct chunk *chunk = obstack_alloc (work, sizeof(struct chunk)); if (data == NULL && size > 0) data = obstack_alloc (work, size); @@ -412,11 +400,10 @@ alloc_chunk (last, data, size, work) } #ifdef ENABLE_JC1_CHECKING -static int CHECK_OP PARAMS ((struct jcf_partial *)); +static int CHECK_OP (struct jcf_partial *); static int -CHECK_OP (state) - struct jcf_partial *state; +CHECK_OP (struct jcf_partial *state) { if (state->bytecode.ptr > state->bytecode.limit) abort (); @@ -428,10 +415,7 @@ CHECK_OP (state) #endif static unsigned char * -append_chunk (data, size, state) - unsigned char *data; - int size; - struct jcf_partial *state; +append_chunk (unsigned char *data, int size, struct jcf_partial *state) { state->chunk = alloc_chunk (state->chunk, data, size, state->chunk_obstack); if (state->first == NULL) @@ -440,21 +424,17 @@ append_chunk (data, size, state) } static void -append_chunk_copy (data, size, state) - unsigned char *data; - int size; - struct jcf_partial *state; +append_chunk_copy (unsigned char *data, int size, struct jcf_partial *state) { unsigned char *ptr = append_chunk (NULL, size, state); memcpy (ptr, data, size); } static struct jcf_block * -gen_jcf_label (state) - struct jcf_partial *state; +gen_jcf_label (struct jcf_partial *state) { - struct jcf_block *block = (struct jcf_block *) - obstack_alloc (state->chunk_obstack, sizeof (struct jcf_block)); + struct jcf_block *block + = obstack_alloc (state->chunk_obstack, sizeof (struct jcf_block)); block->next = NULL; block->linenumber = -1; block->pc = UNDEFINED_PC; @@ -462,8 +442,7 @@ gen_jcf_label (state) } static void -finish_jcf_block (state) - struct jcf_partial *state; +finish_jcf_block (struct jcf_partial *state) { struct jcf_block *block = state->last_block; struct jcf_relocation *reloc; @@ -489,9 +468,7 @@ finish_jcf_block (state) } static void -define_jcf_label (label, state) - struct jcf_block *label; - struct jcf_partial *state; +define_jcf_label (struct jcf_block *label, struct jcf_partial *state) { if (state->last_block != NULL) finish_jcf_block (state); @@ -506,8 +483,7 @@ define_jcf_label (label, state) } static struct jcf_block * -get_jcf_label_here (state) - struct jcf_partial *state; +get_jcf_label_here (struct jcf_partial *state) { if (state->last_block != NULL && BUFFER_LENGTH (&state->bytecode) == 0) return state->last_block; @@ -522,9 +498,7 @@ get_jcf_label_here (state) /* Note a line number entry for the current PC and given LINE. */ static void -put_linenumber (line, state) - int line; - struct jcf_partial *state; +put_linenumber (int line, struct jcf_partial *state) { struct jcf_block *label = get_jcf_label_here (state); if (label->linenumber > 0) @@ -540,13 +514,11 @@ put_linenumber (line, state) in the range (START_LABEL, END_LABEL). */ static struct jcf_handler * -alloc_handler (start_label, end_label, state) - struct jcf_block *start_label; - struct jcf_block *end_label; - struct jcf_partial *state; +alloc_handler (struct jcf_block *start_label, struct jcf_block *end_label, + struct jcf_partial *state) { - struct jcf_handler *handler = (struct jcf_handler *) - obstack_alloc (state->chunk_obstack, sizeof (struct jcf_handler)); + struct jcf_handler *handler + = obstack_alloc (state->chunk_obstack, sizeof (struct jcf_handler)); handler->start_label = start_label; handler->end_label = end_label; handler->handler_label = get_jcf_label_here (state); @@ -564,7 +536,7 @@ alloc_handler (start_label, end_label, state) /* The index of jvm local variable allocated for this DECL. 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.) */ + (We don't allocate DECL_LANG_SPECIFIC for locals from Java source code.) */ #define DECL_LOCAL_INDEX(DECL) DECL_ALIGN(DECL) @@ -582,9 +554,7 @@ struct localvar_info ((struct localvar_info**) state->localvars.ptr - localvar_buffer) static void -localvar_alloc (decl, state) - tree decl; - struct jcf_partial *state; +localvar_alloc (tree decl, struct jcf_partial *state) { struct jcf_block *start_label = get_jcf_label_here (state); int wide = TYPE_IS_WIDE (TREE_TYPE (decl)); @@ -605,8 +575,7 @@ localvar_alloc (decl, state) ptr = (struct localvar_info**) state->localvars.data + index; state->localvars.ptr = (unsigned char *) (ptr + 1 + wide); } - info = (struct localvar_info *) - obstack_alloc (state->chunk_obstack, sizeof (struct localvar_info)); + info = obstack_alloc (state->chunk_obstack, sizeof (struct localvar_info)); ptr[0] = info; if (wide) ptr[1] = (struct localvar_info *)(~0); @@ -629,9 +598,7 @@ localvar_alloc (decl, state) } static void -localvar_free (decl, state) - tree decl; - struct jcf_partial *state; +maybe_free_localvar (tree decl, struct jcf_partial *state, int really) { struct jcf_block *end_label = get_jcf_label_here (state); int index = DECL_LOCAL_INDEX (decl); @@ -643,6 +610,8 @@ localvar_free (decl, state) if (info->decl != decl) abort (); + if (! really) + return; ptr[0] = NULL; if (wide) { @@ -660,8 +629,7 @@ localvar_free (decl, state) a field (FIELD_DECL or VAR_DECL, if static), as encoded in a .class file. */ static int -get_access_flags (decl) - tree decl; +get_access_flags (tree decl) { int flags = 0; int isfield = TREE_CODE (decl) == FIELD_DECL || TREE_CODE (decl) == VAR_DECL; @@ -727,9 +695,7 @@ get_access_flags (decl) /* Write the list of segments starting at CHUNKS to STREAM. */ static void -write_chunks (stream, chunks) - FILE* stream; - struct chunk *chunks; +write_chunks (FILE* stream, struct chunk *chunks) { for (; chunks != NULL; chunks = chunks->next) fwrite (chunks->data, chunks->size, 1, stream); @@ -739,9 +705,7 @@ write_chunks (stream, chunks) (Caller is responsible for doing NOTE_PUSH.) */ static void -push_constant1 (index, state) - HOST_WIDE_INT index; - struct jcf_partial *state; +push_constant1 (HOST_WIDE_INT index, struct jcf_partial *state) { RESERVE (3); if (index < 256) @@ -760,9 +724,7 @@ push_constant1 (index, state) (Caller is responsible for doing NOTE_PUSH.) */ static void -push_constant2 (index, state) - HOST_WIDE_INT index; - struct jcf_partial *state; +push_constant2 (HOST_WIDE_INT index, struct jcf_partial *state) { RESERVE (3); OP1 (OPCODE_ldc2_w); @@ -773,9 +735,7 @@ push_constant2 (index, state) Caller is responsible for doing NOTE_PUSH. */ static void -push_int_const (i, state) - HOST_WIDE_INT i; - struct jcf_partial *state; +push_int_const (HOST_WIDE_INT i, struct jcf_partial *state) { RESERVE(3); if (i >= -1 && i <= 5) @@ -799,9 +759,8 @@ push_int_const (i, state) } static int -find_constant_wide (lo, hi, state) - HOST_WIDE_INT lo, hi; - struct jcf_partial *state; +find_constant_wide (HOST_WIDE_INT lo, HOST_WIDE_INT hi, + struct jcf_partial *state) { HOST_WIDE_INT w1, w2; lshift_double (lo, hi, -32, 64, &w1, &w2, 1); @@ -813,9 +772,7 @@ find_constant_wide (lo, hi, state) Return the index in the constant pool. */ static int -find_constant_index (value, state) - tree value; - struct jcf_partial *state; +find_constant_index (tree value, struct jcf_partial *state) { if (TREE_CODE (value) == INTEGER_CST) { @@ -853,9 +810,7 @@ find_constant_index (value, state) Caller is responsible for doing NOTE_PUSH. */ static void -push_long_const (lo, hi, state) - HOST_WIDE_INT lo, hi; - struct jcf_partial *state; +push_long_const (HOST_WIDE_INT lo, HOST_WIDE_INT hi, struct jcf_partial *state) { HOST_WIDE_INT highpart, dummy; jint lowpart = WORD_TO_INT (lo); @@ -879,10 +834,7 @@ push_long_const (lo, hi, state) } static void -field_op (field, opcode, state) - tree field; - int opcode; - struct jcf_partial *state; +field_op (tree field, int opcode, struct jcf_partial *state) { int index = find_fieldref_index (&state->cpool, field); RESERVE (3); @@ -895,9 +847,7 @@ field_op (field, opcode, state) opcodes typically depend on the operand type. */ static int -adjust_typed_op (type, max) - tree type; - int max; +adjust_typed_op (tree type, int max) { switch (TREE_CODE (type)) { @@ -930,9 +880,7 @@ adjust_typed_op (type, max) } static void -maybe_wide (opcode, index, state) - int opcode, index; - struct jcf_partial *state; +maybe_wide (int opcode, int index, struct jcf_partial *state) { if (index >= 256) { @@ -955,9 +903,7 @@ maybe_wide (opcode, index, state) (The new words get inserted at stack[SP-size-offset].) */ static void -emit_dup (size, offset, state) - int size, offset; - struct jcf_partial *state; +emit_dup (int size, int offset, struct jcf_partial *state) { int kind; if (size == 0) @@ -976,19 +922,14 @@ emit_dup (size, offset, state) } static void -emit_pop (size, state) - int size; - struct jcf_partial *state; +emit_pop (int size, struct jcf_partial *state) { RESERVE (1); OP1 (OPCODE_pop - 1 + size); } static void -emit_iinc (var, value, state) - tree var; - HOST_WIDE_INT value; - struct jcf_partial *state; +emit_iinc (tree var, HOST_WIDE_INT value, struct jcf_partial *state) { int slot = DECL_LOCAL_INDEX (var); @@ -1010,10 +951,9 @@ emit_iinc (var, value, state) } static void -emit_load_or_store (var, opcode, state) - tree var; /* Variable to load from or store into. */ - int opcode; /* Either OPCODE_iload or OPCODE_istore. */ - struct jcf_partial *state; +emit_load_or_store (tree var, /* Variable to load from or store into. */ + int opcode, /* Either OPCODE_iload or OPCODE_istore. */ + struct jcf_partial *state) { tree type = TREE_TYPE (var); int kind = adjust_typed_op (type, 4); @@ -1028,38 +968,29 @@ emit_load_or_store (var, opcode, state) } static void -emit_load (var, state) - tree var; - struct jcf_partial *state; +emit_load (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_store (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_unop (opcode, type, state) - enum java_opcode opcode; - tree type ATTRIBUTE_UNUSED; - struct jcf_partial *state; +emit_unop (enum java_opcode opcode, tree type ATTRIBUTE_UNUSED, + struct jcf_partial *state) { RESERVE(1); OP1 (opcode); } static void -emit_binop (opcode, type, state) - enum java_opcode opcode; - tree type; - struct jcf_partial *state; +emit_binop (enum java_opcode opcode, tree type, struct jcf_partial *state) { int size = TYPE_IS_WIDE (type) ? 2 : 1; RESERVE(1); @@ -1068,14 +999,11 @@ emit_binop (opcode, type, state) } static void -emit_reloc (value, kind, target, state) - HOST_WIDE_INT value; - int kind; - struct jcf_block *target; - struct jcf_partial *state; +emit_reloc (HOST_WIDE_INT value, int kind, + struct jcf_block *target, struct jcf_partial *state) { - struct jcf_relocation *reloc = (struct jcf_relocation *) - obstack_alloc (state->chunk_obstack, sizeof (struct jcf_relocation)); + struct jcf_relocation *reloc + = obstack_alloc (state->chunk_obstack, sizeof (struct jcf_relocation)); struct jcf_block *block = state->last_block; reloc->next = block->u.relocations; block->u.relocations = reloc; @@ -1089,9 +1017,7 @@ emit_reloc (value, kind, target, state) } static void -emit_switch_reloc (label, state) - struct jcf_block *label; - struct jcf_partial *state; +emit_switch_reloc (struct jcf_block *label, struct jcf_partial *state) { emit_reloc (RELOCATION_VALUE_0, BLOCK_START_RELOC, label, state); } @@ -1100,9 +1026,7 @@ emit_switch_reloc (label, state) but re-uses an existing case reloc. */ static void -emit_case_reloc (reloc, state) - struct jcf_relocation *reloc; - struct jcf_partial *state; +emit_case_reloc (struct jcf_relocation *reloc, struct jcf_partial *state) { struct jcf_block *block = state->last_block; reloc->next = block->u.relocations; @@ -1116,10 +1040,8 @@ emit_case_reloc (reloc, state) 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; +emit_if (struct jcf_block *target, int opcode, int inv_opcode, + struct jcf_partial *state) { RESERVE(3); OP1 (opcode); @@ -1128,9 +1050,7 @@ emit_if (target, opcode, inv_opcode, state) } static void -emit_goto (target, state) - struct jcf_block *target; - struct jcf_partial *state; +emit_goto (struct jcf_block *target, struct jcf_partial *state) { RESERVE(3); OP1 (OPCODE_goto); @@ -1139,30 +1059,27 @@ emit_goto (target, state) } static void -emit_jsr (target, state) - struct jcf_block *target; - struct jcf_partial *state; +emit_jsr (struct jcf_block *target, struct jcf_partial *state) { RESERVE(3); OP1 (OPCODE_jsr); /* Value is 1 byte from reloc back to start of instruction. */ emit_reloc (RELOCATION_VALUE_1, OPCODE_jsr_w, target, state); + state->num_jsrs++; } /* Generate code to evaluate EXP. If the result is true, branch to TRUE_LABEL; otherwise, branch to FALSE_LABEL. - TRUE_BRANCH_FIRST is a code geneation hint that the + TRUE_BRANCH_FIRST is a code generation 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:) */ static void -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; +generate_bytecode_conditional (tree exp, + struct jcf_block *true_label, + struct jcf_block *false_label, + int true_branch_first, + struct jcf_partial *state) { tree exp0, exp1, type; int save_SP = state->code_SP; @@ -1310,7 +1227,7 @@ generate_bytecode_conditional (exp, true_label, false_label, OP1 (OPCODE_lcmp); goto compare_1; } - /* FALLTHOUGH */ + /* FALLTHROUGH */ default: if (integer_zerop (exp1)) { @@ -1367,9 +1284,7 @@ generate_bytecode_conditional (exp, true_label, false_label, emit label that is LIMIT). */ static void -call_cleanups (limit, state) - struct jcf_block *limit; - struct jcf_partial *state; +call_cleanups (struct jcf_block *limit, struct jcf_partial *state) { struct jcf_block *block = state->labeled_blocks; for (; block != limit; block = block->next) @@ -1380,9 +1295,7 @@ call_cleanups (limit, state) } static void -generate_bytecode_return (exp, state) - tree exp; - struct jcf_partial *state; +generate_bytecode_return (tree exp, struct jcf_partial *state) { tree return_type = TREE_TYPE (TREE_TYPE (state->current_method)); int returns_void = TREE_CODE (return_type) == VOID_TYPE; @@ -1434,7 +1347,7 @@ generate_bytecode_return (exp, state) emit_store (state->return_value_decl, state); call_cleanups (NULL, state); emit_load (state->return_value_decl, state); - /* If we call localvar_free (state->return_value_decl, state), + /* If we call maybe_free_localvar (state->return_value_decl, state, 1), then we risk the save decl erroneously re-used in the finalizer. Instead, we keep the state->return_value_decl allocated through the rest of the method. This is not @@ -1449,10 +1362,7 @@ generate_bytecode_return (exp, state) 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; +generate_bytecode_insns (tree exp, int target, struct jcf_partial *state) { tree type, arg; enum java_opcode jopcode; @@ -1474,6 +1384,7 @@ generate_bytecode_insns (exp, target, state) { tree local; tree body = BLOCK_EXPR_BODY (exp); + long jsrs = state->num_jsrs; for (local = BLOCK_EXPR_DECLS (exp); local; ) { tree next = TREE_CHAIN (local); @@ -1487,10 +1398,11 @@ generate_bytecode_insns (exp, target, state) body = TREE_OPERAND (body, 1); } generate_bytecode_insns (body, target, state); + for (local = BLOCK_EXPR_DECLS (exp); local; ) { tree next = TREE_CHAIN (local); - localvar_free (local, state); + maybe_free_localvar (local, state, state->num_jsrs <= jsrs); local = next; } } @@ -1507,17 +1419,17 @@ generate_bytecode_insns (exp, target, state) { const char *saved_input_filename = input_filename; tree body = EXPR_WFL_NODE (exp); - int saved_lineno = lineno; + int saved_lineno = input_line; if (body == empty_stmt_node) break; input_filename = EXPR_WFL_FILENAME (exp); - lineno = EXPR_WFL_LINENO (exp); - if (EXPR_WFL_EMIT_LINE_NOTE (exp) && lineno > 0 + input_line = EXPR_WFL_LINENO (exp); + if (EXPR_WFL_EMIT_LINE_NOTE (exp) && input_line > 0 && debug_info_level > DINFO_LEVEL_NONE) - put_linenumber (lineno, state); + put_linenumber (input_line, state); generate_bytecode_insns (body, target, state); input_filename = saved_input_filename; - lineno = saved_lineno; + input_line = saved_lineno; } break; case INTEGER_CST: @@ -1550,8 +1462,9 @@ generate_bytecode_insns (exp, target, state) OP1 (prec == 1 ? OPCODE_fconst_0 : OPCODE_dconst_0); else if (real_onep (exp)) OP1 (prec == 1 ? OPCODE_fconst_1 : OPCODE_dconst_1); - /* FIXME Should also use fconst_2 for 2.0f. - Also, should use iconst_2/ldc followed by i2f/i2d + else if (prec == 1 && real_twop (exp)) + OP1 (OPCODE_fconst_2); + /* ??? We could also use iconst_3/ldc followed by i2f/i2d for other float/double when the value is a small integer. */ else { @@ -1668,8 +1581,8 @@ generate_bytecode_insns (exp, target, state) case CASE_EXPR: { struct jcf_switch_state *sw_state = state->sw_state; - struct jcf_relocation *reloc = (struct jcf_relocation *) - obstack_alloc (state->chunk_obstack, sizeof (struct jcf_relocation)); + struct jcf_relocation *reloc + = obstack_alloc (state->chunk_obstack, sizeof (struct jcf_relocation)); HOST_WIDE_INT case_value = TREE_INT_CST_LOW (TREE_OPERAND (exp, 0)); reloc->kind = 0; reloc->label = get_jcf_label_here (state); @@ -1749,8 +1662,8 @@ generate_bytecode_insns (exp, target, state) HOST_WIDE_INT i; unsigned HOST_WIDE_INT delta; /* Copy the chain of relocs into a sorted array. */ - struct jcf_relocation **relocs = (struct jcf_relocation **) - xmalloc (sw_state.num_cases * sizeof (struct jcf_relocation *)); + struct jcf_relocation **relocs + = xmalloc (sw_state.num_cases * sizeof (struct jcf_relocation *)); /* The relocs arrays is a buffer with a gap. The assumption is that cases will normally come in "runs". */ int gap_start = 0; @@ -1784,7 +1697,7 @@ generate_bytecode_insns (exp, target, state) something like Integer.MIN_VALUE. That is why delta is unsigned. */ delta = sw_state.max_case - sw_state.min_case; - if (2 * sw_state.num_cases >= delta) + if (2 * (unsigned) sw_state.num_cases >= delta) { /* Use tableswitch. */ int index = 0; RESERVE (13 + 4 * (sw_state.max_case - sw_state.min_case + 1)); @@ -2117,7 +2030,7 @@ generate_bytecode_insns (exp, target, state) emit_dup (TYPE_IS_WIDE (type) ? 2 : 1 , offset, state); exp = lhs; } - /* FALLTHOUGH */ + /* FALLTHROUGH */ finish_assignment: if (TREE_CODE (exp) == COMPONENT_REF) @@ -2182,10 +2095,10 @@ generate_bytecode_insns (exp, target, state) tree arg0 = TREE_OPERAND (exp, 0); tree arg1 = TREE_OPERAND (exp, 1); jopcode += adjust_typed_op (type, 3); - if (arg0 == arg1 && TREE_CODE (arg0) == SAVE_EXPR) + if (arg0 != NULL_TREE && operand_equal_p (arg0, arg1, 0)) { /* fold may (e.g) convert 2*x to x+x. */ - generate_bytecode_insns (TREE_OPERAND (arg0, 0), target, state); + generate_bytecode_insns (arg0, target, state); emit_dup (TYPE_PRECISION (TREE_TYPE (arg0)) > 32 ? 2 : 1, 0, state); } else @@ -2444,8 +2357,8 @@ generate_bytecode_insns (exp, target, state) if (CAN_COMPLETE_NORMALLY (finally)) { maybe_wide (OPCODE_ret, DECL_LOCAL_INDEX (return_link), state); - localvar_free (exception_decl, state); - localvar_free (return_link, state); + maybe_free_localvar (exception_decl, state, 1); + maybe_free_localvar (return_link, state, 1); define_jcf_label (finished_label, state); } } @@ -2501,6 +2414,23 @@ generate_bytecode_insns (exp, target, state) case JAVA_EXC_OBJ_EXPR: NOTE_PUSH (1); /* Pushed by exception system. */ break; + case MIN_EXPR: + case MAX_EXPR: + { + /* This copes with cases where fold() has created MIN or MAX + from a conditional expression. */ + enum tree_code code = TREE_CODE (exp) == MIN_EXPR ? LT_EXPR : GT_EXPR; + tree op0 = TREE_OPERAND (exp, 0); + tree op1 = TREE_OPERAND (exp, 1); + tree x; + if (TREE_SIDE_EFFECTS (op0) || TREE_SIDE_EFFECTS (op1)) + abort (); + x = build (COND_EXPR, TREE_TYPE (exp), + build (code, boolean_type_node, op0, op1), + op0, op1); + generate_bytecode_insns (x, target, state); + break; + } case NEW_CLASS_EXPR: { tree class = TREE_TYPE (TREE_TYPE (exp)); @@ -2647,8 +2577,7 @@ generate_bytecode_insns (exp, target, state) } static void -perform_relocations (state) - struct jcf_partial *state; +perform_relocations (struct jcf_partial *state) { struct jcf_block *block; struct jcf_relocation *reloc; @@ -2756,8 +2685,7 @@ perform_relocations (state) unsigned char *old_ptr = old_buffer + old_size; if (new_size != old_size) { - chunk->data = (unsigned char *) - obstack_alloc (state->chunk_obstack, new_size); + chunk->data = obstack_alloc (state->chunk_obstack, new_size); chunk->size = new_size; } new_ptr = chunk->data + new_size; @@ -2846,9 +2774,7 @@ perform_relocations (state) } static void -init_jcf_state (state, work) - struct jcf_partial *state; - struct obstack *work; +init_jcf_state (struct jcf_partial *state, struct obstack *work) { state->chunk_obstack = work; state->first = state->chunk = NULL; @@ -2858,9 +2784,7 @@ init_jcf_state (state, work) } static void -init_jcf_method (state, method) - struct jcf_partial *state; - tree method; +init_jcf_method (struct jcf_partial *state, tree method) { state->current_method = method; state->blocks = state->last_block = NULL; @@ -2881,8 +2805,7 @@ init_jcf_method (state, method) } static void -release_jcf_state (state) - struct jcf_partial *state; +release_jcf_state (struct jcf_partial *state) { CPOOL_FINISH (&state->cpool); obstack_free (state->chunk_obstack, state->first); @@ -2894,9 +2817,7 @@ release_jcf_state (state) static GTY(()) tree SourceFile_node; static struct chunk * -generate_classfile (clas, state) - tree clas; - struct jcf_partial *state; +generate_classfile (tree clas, struct jcf_partial *state) { struct chunk *cpool_chunk; const char *source_file, *s; @@ -2919,7 +2840,7 @@ generate_classfile (clas, state) append_chunk (NULL, 0, state); cpool_chunk = state->chunk; - /* Next allocate the chunk containing acces_flags through fields_counr. */ + /* Next allocate the chunk containing acces_flags through fields_count. */ if (clas == object_type_node) i = 10; else @@ -2970,8 +2891,11 @@ generate_classfile (clas, state) if (have_value) attr_count++; - if (FIELD_THISN (part) || FIELD_LOCAL_ALIAS (part) || FIELD_SYNTHETIC (part)) + if (FIELD_THISN (part) || FIELD_LOCAL_ALIAS (part) + || FIELD_SYNTHETIC (part)) attr_count++; + if (FIELD_DEPRECATED (part)) + attr_count++; PUT2 (attr_count); /* attributes_count */ if (have_value) @@ -2993,6 +2917,8 @@ generate_classfile (clas, state) if (FIELD_THISN (part) || FIELD_LOCAL_ALIAS (part) || FIELD_SYNTHETIC (part)) ptr = append_synthetic_attribute (state); + if (FIELD_DEPRECATED (part)) + append_deprecated_attribute (state); fields_count++; } ptr = fields_count_ptr; UNSAFE_PUT2 (fields_count); @@ -3011,6 +2937,12 @@ generate_classfile (clas, state) tree type = TREE_TYPE (part); tree save_function = current_function_decl; int synthetic_p = 0; + + /* Invisible Miranda methods shouldn't end up in the .class + file. */ + if (METHOD_INVISIBLE (part)) + continue; + current_function_decl = part; ptr = append_chunk (NULL, 8, state); i = get_access_flags (part); PUT2 (i); @@ -3028,6 +2960,9 @@ generate_classfile (clas, state) i++; synthetic_p = 1; } + /* Make room for Deprecated attribute. */ + if (METHOD_DEPRECATED (part)) + i++; PUT2 (i); /* attributes_count */ @@ -3050,6 +2985,7 @@ generate_classfile (clas, state) get_jcf_label_here (state); /* Force a first block. */ for (t = DECL_ARGUMENTS (part); t != NULL_TREE; t = TREE_CHAIN (t)) localvar_alloc (t, state); + state->num_jsrs = 0; generate_bytecode_insns (body, IGNORE_TARGET, state); if (CAN_COMPLETE_NORMALLY (body)) { @@ -3059,9 +2995,9 @@ generate_classfile (clas, state) OP1 (OPCODE_return); } for (t = DECL_ARGUMENTS (part); t != NULL_TREE; t = TREE_CHAIN (t)) - localvar_free (t, state); + maybe_free_localvar (t, state, 1); if (state->return_value_decl != NULL_TREE) - localvar_free (state->return_value_decl, state); + maybe_free_localvar (state->return_value_decl, state, 1); finish_jcf_block (state); perform_relocations (state); @@ -3168,6 +3104,10 @@ generate_classfile (clas, state) PUT2 (i); } } + + if (METHOD_DEPRECATED (part)) + append_deprecated_attribute (state); + methods_count++; current_function_decl = save_function; } @@ -3189,6 +3129,9 @@ generate_classfile (clas, state) i++; if (clas == object_type_node) i++; + if (CLASS_DEPRECATED (TYPE_NAME (clas))) + i++; + PUT2 (i); /* attributes_count */ /* generate the SourceFile attribute. */ @@ -3204,6 +3147,8 @@ generate_classfile (clas, state) PUT2 (i); append_gcj_attribute (state, clas); append_innerclasses_attribute (state, clas); + if (CLASS_DEPRECATED (TYPE_NAME (clas))) + append_deprecated_attribute (state); /* New finally generate the contents of the constant pool chunk. */ i = count_constant_pool_bytes (&state->cpool); @@ -3216,8 +3161,7 @@ generate_classfile (clas, state) static GTY(()) tree Synthetic_node; static unsigned char * -append_synthetic_attribute (state) - struct jcf_partial *state; +append_synthetic_attribute (struct jcf_partial *state) { unsigned char *ptr = append_chunk (NULL, 6, state); int i; @@ -3234,9 +3178,18 @@ append_synthetic_attribute (state) } static void -append_gcj_attribute (state, class) - struct jcf_partial *state; - tree class; +append_deprecated_attribute (struct jcf_partial *state) +{ + unsigned char *ptr = append_chunk (NULL, 6, state); + int i; + + i = find_utf8_constant (&state->cpool, get_identifier ("Deprecated")); + PUT2 (i); /* Attribute string index */ + PUT4 (0); /* Attribute length */ +} + +static void +append_gcj_attribute (struct jcf_partial *state, tree class) { unsigned char *ptr; int i; @@ -3253,9 +3206,7 @@ append_gcj_attribute (state, class) static tree InnerClasses_node; static void -append_innerclasses_attribute (state, class) - struct jcf_partial *state; - tree class; +append_innerclasses_attribute (struct jcf_partial *state, tree class) { tree orig_decl = TYPE_NAME (class); tree current, decl; @@ -3308,9 +3259,8 @@ append_innerclasses_attribute (state, class) } static void -append_innerclasses_attribute_entry (state, decl, name) - struct jcf_partial *state; - tree decl, name; +append_innerclasses_attribute_entry (struct jcf_partial *state, + tree decl, tree name) { int icii, icaf; int ocii = 0, ini = 0; @@ -3334,12 +3284,12 @@ append_innerclasses_attribute_entry (state, decl, name) } static char * -make_class_file_name (clas) - tree clas; +make_class_file_name (tree clas) { const char *dname, *cname, *slash; char *r; struct stat sb; + char sep; cname = IDENTIFIER_POINTER (identifier_subst (DECL_NAME (TYPE_NAME (clas)), "", '.', DIR_SEPARATOR, @@ -3351,24 +3301,45 @@ make_class_file_name (clas) char *t; dname = DECL_SOURCE_FILE (TYPE_NAME (clas)); slash = strrchr (dname, DIR_SEPARATOR); +#ifdef DIR_SEPARATOR_2 if (! slash) - { - dname = "."; - slash = dname + 1; - } + slash = strrchr (dname, DIR_SEPARATOR_2); +#endif + if (! slash) + { + dname = "."; + slash = dname + 1; + sep = DIR_SEPARATOR; + } + else + sep = *slash; + t = strrchr (cname, DIR_SEPARATOR); if (t) cname = t + 1; } else { + char *s; + dname = jcf_write_base_directory; + + s = strrchr (dname, DIR_SEPARATOR); +#ifdef DIR_SEPARATOR_2 + if (! s) + s = strrchr (dname, DIR_SEPARATOR_2); +#endif + if (s) + sep = *s; + else + sep = DIR_SEPARATOR; + slash = dname + strlen (dname); } r = xmalloc (slash - dname + strlen (cname) + 2); strncpy (r, dname, slash - dname); - r[slash - dname] = DIR_SEPARATOR; + r[slash - dname] = sep; strcpy (&r[slash - dname + 1], cname); /* We try to make new directories when we need them. We only do @@ -3380,30 +3351,29 @@ make_class_file_name (clas) dname = r + (slash - dname) + 1; while (1) { - char *s = strchr (dname, DIR_SEPARATOR); + char *s = strchr (dname, sep); if (s == NULL) break; *s = '\0'; if (stat (r, &sb) == -1 /* Try to make it. */ && mkdir (r, 0755) == -1) - fatal_io_error ("can't create directory %s", r); + fatal_error ("can't create directory %s: %m", r); - *s = DIR_SEPARATOR; + *s = sep; /* Skip consecutive separators. */ - for (dname = s + 1; *dname && *dname == DIR_SEPARATOR; ++dname) + for (dname = s + 1; *dname && *dname == sep; ++dname) ; } return r; } -/* Write out the contens of a class (RECORD_TYPE) CLAS, as a .class file. +/* Write out the contents of a class (RECORD_TYPE) CLAS, as a .class file. The output .class file name is make_class_file_name(CLAS). */ void -write_classfile (clas) - tree clas; +write_classfile (tree clas) { struct obstack *work = &temporary_obstack; struct jcf_partial state[1]; @@ -3421,14 +3391,14 @@ write_classfile (clas) temporary_file_name = concat (class_file_name, ".tmp", NULL); stream = fopen (temporary_file_name, "wb"); if (stream == NULL) - fatal_io_error ("can't open %s for writing", temporary_file_name); + fatal_error ("can't open %s for writing: %m", temporary_file_name); jcf_dependency_add_target (class_file_name); init_jcf_state (state, work); chunks = generate_classfile (clas, state); write_chunks (stream, chunks); if (fclose (stream)) - fatal_io_error ("error closing %s", temporary_file_name); + fatal_error ("error closing %s: %m", temporary_file_name); /* If a file named by the string pointed to by `new' exists prior to the call to the `rename' function, the bahaviour @@ -3441,7 +3411,7 @@ write_classfile (clas) if (rename (temporary_file_name, class_file_name) == -1) { remove (temporary_file_name); - fatal_io_error ("can't create %s", class_file_name); + fatal_error ("can't create %s: %m", class_file_name); } free (temporary_file_name); free (class_file_name);