This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
[ecj] Patch: FYI: remove jcf-write.c
- From: Tom Tromey <tromey at redhat dot com>
- To: Java Patch List <java-patches at gcc dot gnu dot org>
- Date: 20 Oct 2006 14:41:41 -0600
- Subject: [ecj] Patch: FYI: remove jcf-write.c
- Reply-to: tromey at redhat dot com
I'm checking this in on the gcj-eclipse branch.
This removes jcf-write.c, the old class file generator.
This is now handled by ecj.
Tom
Index: ChangeLog
from Tom Tromey <tromey@redhat.com>
* lang.c (java_handle_option): Don't use
jcf_write_base_directory.
* jcf.h (jcf_write_base_directory): Removed.
* parse.y (java_expand_classes): Don't call write_classfile.
* config-lang.in (gtfiles): Removed jcf-write.c.
* Make-lang.in (JAVA_OBJS): Removed jcf-write.o.
(java/jcf-write.o): Removed.
* jcf-parse.c (parse_class_file): Don't call write_classfile.
* java-tree.h (write_classfile): Removed declaration.
* jcf-write.c: Removed.
Index: parse.y
===================================================================
--- parse.y (revision 117511)
+++ parse.y (working copy)
@@ -9397,9 +9397,7 @@
current = TREE_CHAIN (current))
{
output_class = current_class = TREE_TYPE (TREE_VALUE (current));
- if (flag_emit_class_files)
- write_classfile (current_class);
- else if (! flag_syntax_only)
+ if (! flag_emit_class_files && ! flag_syntax_only)
java_expand_method_bodies (current_class);
}
}
Index: config-lang.in
===================================================================
--- config-lang.in (revision 117911)
+++ config-lang.in (working copy)
@@ -36,7 +36,7 @@
stagestuff="jc1\$(exeext) gcj\$(exeext) jvgenmain\$(exeext) jv-scan\$(exeext) jcf-dump\$(exeext)"
-gtfiles="\$(srcdir)/java/java-tree.h \$(srcdir)/java/jcf.h \$(srcdir)/java/lex.h \$(srcdir)/java/parse.h \$(srcdir)/java/builtins.c \$(srcdir)/java/class.c \$(srcdir)/java/constants.c \$(srcdir)/java/decl.c \$(srcdir)/java/expr.c \$(srcdir)/java/jcf-parse.c \$(srcdir)/java/jcf-write.c \$(srcdir)/java/lang.c \$(srcdir)/java/mangle.c \$(srcdir)/java/parse.y \$(srcdir)/java/resource.c"
+gtfiles="\$(srcdir)/java/java-tree.h \$(srcdir)/java/jcf.h \$(srcdir)/java/lex.h \$(srcdir)/java/parse.h \$(srcdir)/java/builtins.c \$(srcdir)/java/class.c \$(srcdir)/java/constants.c \$(srcdir)/java/decl.c \$(srcdir)/java/expr.c \$(srcdir)/java/jcf-parse.c \$(srcdir)/java/lang.c \$(srcdir)/java/mangle.c \$(srcdir)/java/parse.y \$(srcdir)/java/resource.c"
target_libs=${libgcj_saved}
lang_dirs="zlib fastjar"
Index: jcf-parse.c
===================================================================
--- jcf-parse.c (revision 117511)
+++ jcf-parse.c (working copy)
@@ -1140,9 +1140,6 @@
end_java_method ();
}
- if (flag_emit_class_files)
- write_classfile (current_class);
-
finish_class ();
(*debug_hooks->end_source_file) (LOCATION_LINE (save_location));
Index: Make-lang.in
===================================================================
--- Make-lang.in (revision 117911)
+++ Make-lang.in (working copy)
@@ -102,7 +102,7 @@
java/verify-glue.o java/verify-impl.o \
java/zextract.o java/jcf-io.o java/win32-host.o java/jcf-parse.o java/mangle.o \
java/mangle_name.o java/builtins.o java/resource.o \
- java/jcf-write.o java/buffer.o java/check-init.o java/jcf-depend.o \
+ java/buffer.o java/check-init.o java/jcf-depend.o \
java/jcf-path.o java/boehm.o java/java-gimplify.o
JVSCAN_OBJS = java/parse-scan.o java/jv-scan.o version.o intl.o
@@ -289,9 +289,6 @@
java/jcf-parse.o: java/jcf-parse.c $(CONFIG_H) $(JAVA_TREE_H) flags.h \
input.h java/java-except.h $(SYSTEM_H) coretypes.h $(TM_H) toplev.h \
java/parse.h $(GGC_H) debug.h real.h gt-java-jcf-parse.h $(TM_P_H)
-java/jcf-write.o: java/jcf-write.c $(CONFIG_H) $(JAVA_TREE_H) java/jcf.h \
- $(RTL_H) java/java-opcodes.h java/parse.h java/buffer.h $(SYSTEM_H) \
- coretypes.h $(TM_H) toplev.h $(GGC_H) gt-java-jcf-write.h $(TM_P_H)
java/jv-scan.o: java/jv-scan.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
version.h intl.h
java/jvgenmain.o: java/jvgenmain.c $(CONFIG_H) $(JAVA_TREE_H) $(SYSTEM_H) \
Index: jcf-write.c
===================================================================
--- jcf-write.c (revision 117511)
+++ jcf-write.c (working copy)
@@ -1,3565 +0,0 @@
-/* Write out a Java(TM) class file.
- Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
- Free Software Foundation, Inc.
-
-This file is part of GCC.
-
-GCC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GCC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.
-
-Java and all Java-based marks are trademarks or registered trademarks
-of Sun Microsystems, Inc. in the United States and other countries.
-The Free Software Foundation is independent of Sun Microsystems, Inc. */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tm.h"
-#include "jcf.h"
-#include "tree.h"
-#include "real.h"
-#include "java-tree.h"
-#include "obstack.h"
-#include "rtl.h"
-#include "flags.h"
-#include "java-opcodes.h"
-#include "parse.h" /* for BLOCK_EXPR_BODY */
-#include "buffer.h"
-#include "toplev.h"
-#include "ggc.h"
-#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. */
-const char *jcf_write_base_directory = NULL;
-
-/* Make sure bytecode.data is big enough for at least N more bytes. */
-
-#define RESERVE(N) \
- do { CHECK_OP(state); \
- 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) (*state->bytecode.ptr++ = (I), CHECK_OP(state))
-
-/* Like OP1, but I is a 2-byte big endian integer. */
-
-#define OP2(I) \
- do { int _i = (I); OP1 (_i >> 8); OP1 (_i); CHECK_OP(state); } while (0)
-
-/* Like OP1, but I is a 4-byte big endian integer. */
-
-#define OP4(I) \
- do { int _i = (I); OP1 (_i >> 24); OP1 (_i >> 16); \
- OP1 (_i >> 8); OP1 (_i); CHECK_OP(state); } while (0)
-
-/* Macro to call each time we push I words on the JVM stack. */
-
-#define NOTE_PUSH(I) \
- 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 { state->code_SP -= (I); gcc_assert (state->code_SP >= 0); } while (0)
-
-/* A chunk or segment of a .class file. */
-
-struct chunk
-{
- /* The next segment of this .class file. */
- struct chunk *next;
-
- /* The actual data in this segment to be written to the .class file. */
- unsigned char *data;
-
- /* The size of the segment to be written to the .class file. */
- int size;
-};
-
-#define PENDING_CLEANUP_PC (-3)
-#define PENDING_EXIT_PC (-2)
-#define UNDEFINED_PC (-1)
-
-/* 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.
-
- If (pc < 0), the jcf_block is not an actual block (i.e. it has no
- associated code yet), but it is an undefined label.
-*/
-
-struct jcf_block
-{
- /* For blocks that that are defined, the next block (in pc order).
- For blocks that are not-yet-defined the end label of a LABELED_BLOCK_EXPR
- or a cleanup expression (from a TRY_FINALLY_EXPR),
- this is the next (outer) such end label, in a stack headed by
- labeled_blocks in jcf_partial. */
- struct jcf_block *next;
-
- /* In the not-yet-defined end label for an unfinished EXIT_BLOCK_EXPR.
- pc is PENDING_EXIT_PC.
- In the not-yet-defined end label for pending cleanup subroutine,
- pc is PENDING_CLEANUP_PC.
- For other not-yet-defined labels, pc is UNDEFINED_PC.
-
- If the label has been defined:
- Until perform_relocations is finished, this is the maximum possible
- value of the bytecode offset at the beginning of this block.
- After perform_relocations, it is the actual offset (pc). */
- int pc;
-
- int linenumber;
-
- /* After finish_jcf_block is called, the actual instructions
- contained in this block. Before that NULL, and the instructions
- are in state->bytecode. */
- union {
- struct chunk *chunk;
-
- /* If pc==PENDING_CLEANUP_PC, start_label is the start of the region
- covered by the cleanup. */
- struct jcf_block *start_label;
- } v;
-
- 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.
- If pc==PENDING_CLEANUP_PC, the cleanup that needs to be run. */
- tree labeled_block;
- } u;
-};
-
-/* A "relocation" type for the 0-3 bytes of padding at the start
- of a tableswitch or a lookupswitch. */
-#define SWITCH_ALIGN_RELOC 4
-
-/* A relocation type for the labels in a tableswitch or a lookupswitch;
- these are relative to the start of the instruction, but (due to
- th 0-3 bytes of padding), we don't know the offset before relocation. */
-#define BLOCK_START_RELOC 1
-
-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. */
- HOST_WIDE_INT offset;
-
- /* 0 if offset is a 4-byte relative offset.
- 4 (SWITCH_ALIGN_RELOC) if offset points to 0-3 padding bytes inserted
- for proper alignment in tableswitch/lookupswitch instructions.
- 1 (BLOCK_START_RELOC) if offset points to a 4-byte offset relative
- to the start of the containing block.
- -1 if offset is a 2-byte relative offset.
- < -1 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.
- > 4 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;
-};
-
-#define RELOCATION_VALUE_0 ((HOST_WIDE_INT)0)
-#define RELOCATION_VALUE_1 ((HOST_WIDE_INT)1)
-
-/* State for single catch clause. */
-
-struct jcf_handler
-{
- struct jcf_handler *next;
-
- struct jcf_block *start_label;
- struct jcf_block *end_label;
- struct jcf_block *handler_label;
-
- /* The sub-class of Throwable handled, or NULL_TREE (for finally). */
- tree type;
-};
-
-/* State for the current switch statement. */
-
-struct jcf_switch_state
-{
- struct jcf_switch_state *prev;
- struct jcf_block *default_label;
-
- struct jcf_relocation *cases;
- int num_cases;
- HOST_WIDE_INT min_case, max_case;
-};
-
-/* 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;
-
- /* Chain of exception handlers for the current method. */
- struct jcf_handler *handlers;
-
- /* Last element in handlers chain. */
- struct jcf_handler *last_handler;
-
- /* Number of exception handlers for the current method. */
- int num_handlers;
-
- /* Number of finalizers we are currently nested within. */
- int num_finalizers;
-
- /* If non-NULL, use this for the return value. */
- tree return_value_decl;
-
- /* Information about the current switch statement. */
- struct jcf_switch_state *sw_state;
-
- /* The count of jsr instructions that have been emitted. */
- long num_jsrs;
-};
-
-static void generate_bytecode_insns (tree, int, struct jcf_partial *);
-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 int get_classfile_modifiers (tree class);
-static struct chunk * generate_classfile (tree, struct jcf_partial *);
-static struct jcf_handler *alloc_handler (struct jcf_block *,
- struct jcf_block *,
- 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 (void *, struct jcf_partial *, int);
-
-static int
-CHECK_PUT (void *ptr, struct jcf_partial *state, int i)
-{
- gcc_assert ((unsigned char *) ptr >= state->chunk->data
- && (unsigned char *) ptr + i <= state->chunk->data + state->chunk->size);
- return 0;
-}
-#else
-#define CHECK_PUT(PTR, STATE, I) ((void)0)
-#endif
-
-#define PUT1(X) (CHECK_PUT(ptr, state, 1), *ptr++ = (X))
-#define PUT2(X) (PUT1((X) >> 8), PUT1((X) & 0xFF))
-#define PUT4(X) (PUT2((X) >> 16), PUT2((X) & 0xFFFF))
-#define PUTN(P, N) (CHECK_PUT(ptr, state, N), memcpy(ptr, P, N), ptr += (N))
-
-/* There are some cases below where CHECK_PUT is guaranteed to fail.
- Use the following macros in those specific cases. */
-#define UNSAFE_PUT1(X) (*ptr++ = (X))
-#define UNSAFE_PUT2(X) (UNSAFE_PUT1((X) >> 8), UNSAFE_PUT1((X) & 0xFF))
-#define UNSAFE_PUT4(X) (UNSAFE_PUT2((X) >> 16), UNSAFE_PUT2((X) & 0xFFFF))
-#define UNSAFE_PUTN(P, N) (memcpy(ptr, P, N), ptr += (N))
-
-
-/* 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. */
-
-static struct chunk *
-alloc_chunk (struct chunk *last, unsigned char *data,
- int size, struct obstack *work)
-{
- struct chunk *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;
-}
-
-#ifdef ENABLE_JC1_CHECKING
-static int CHECK_OP (struct jcf_partial *);
-
-static int
-CHECK_OP (struct jcf_partial *state)
-{
- gcc_assert (state->bytecode.ptr <= state->bytecode.limit);
- return 0;
-}
-#else
-#define CHECK_OP(STATE) ((void) 0)
-#endif
-
-static unsigned char *
-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)
- state->first = state->chunk;
- return state->chunk->data;
-}
-
-static void
-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 (struct jcf_partial *state)
-{
- struct jcf_block *block
- = obstack_alloc (state->chunk_obstack, sizeof (struct jcf_block));
- block->next = NULL;
- block->linenumber = -1;
- block->pc = UNDEFINED_PC;
- return block;
-}
-
-static void
-finish_jcf_block (struct jcf_partial *state)
-{
- struct jcf_block *block = state->last_block;
- struct jcf_relocation *reloc;
- int code_length = BUFFER_LENGTH (&state->bytecode);
- int pc = state->code_length;
- append_chunk_copy (state->bytecode.data, code_length, state);
- BUFFER_RESET (&state->bytecode);
- block->v.chunk = state->chunk;
-
- /* Calculate code_length to the maximum value it can have. */
- pc += block->v.chunk->size;
- for (reloc = block->u.relocations; reloc != NULL; reloc = reloc->next)
- {
- int kind = reloc->kind;
- if (kind == SWITCH_ALIGN_RELOC)
- pc += 3;
- else if (kind > BLOCK_START_RELOC)
- 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;
-}
-
-static void
-define_jcf_label (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;
-}
-
-static struct jcf_block *
-get_jcf_label_here (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;
- }
-}
-
-/* Note a line number entry for the current PC and given LINE. */
-
-static void
-put_linenumber (int line, struct jcf_partial *state)
-{
- struct jcf_block *label = get_jcf_label_here (state);
- if (label->linenumber > 0)
- {
- label = gen_jcf_label (state);
- define_jcf_label (label, state);
- }
- label->linenumber = line;
- state->linenumber_count++;
-}
-
-/* Allocate a new jcf_handler, for a catch clause that catches exceptions
- in the range (START_LABEL, END_LABEL). */
-
-static struct jcf_handler *
-alloc_handler (struct jcf_block *start_label, struct jcf_block *end_label,
- struct jcf_partial *state)
-{
- 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);
- if (state->handlers == NULL)
- state->handlers = handler;
- else
- state->last_handler->next = handler;
- state->last_handler = handler;
- handler->next = NULL;
- state->num_handlers++;
- return handler;
-}
-
-
-/* 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 source code.) */
-
-#define DECL_LOCAL_INDEX(DECL) DECL_ALIGN(DECL)
-
-struct localvar_info
-{
- struct localvar_info *next;
-
- tree decl;
- struct jcf_block *start_label;
- struct jcf_block *end_label;
-};
-
-#define localvar_buffer ((struct localvar_info**) state->localvars.data)
-#define localvar_max \
- ((struct localvar_info**) state->localvars.ptr - localvar_buffer)
-
-static void
-localvar_alloc (tree decl, struct jcf_partial *state)
-{
- struct jcf_block *start_label = get_jcf_label_here (state);
- int wide = TYPE_IS_WIDE (TREE_TYPE (decl));
- int index;
- struct localvar_info *info;
- struct localvar_info **ptr = localvar_buffer;
- struct localvar_info **limit
- = (struct localvar_info**) state->localvars.ptr;
- for (index = 0; ptr < limit; index++, ptr++)
- {
- if (ptr[0] == NULL
- && (! wide || ((ptr+1) < limit && ptr[1] == NULL)))
- break;
- }
- if (ptr == limit)
- {
- 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 = obstack_alloc (state->chunk_obstack, sizeof (struct localvar_info));
- ptr[0] = info;
- if (wide)
- ptr[1] = (struct localvar_info *)(~0);
- DECL_LOCAL_INDEX (decl) = index;
- info->decl = decl;
- info->start_label = start_label;
-
- if (debug_info_level > DINFO_LEVEL_TERSE
- && DECL_NAME (decl) != NULL_TREE)
- {
- /* Generate debugging info. */
- 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++;
- }
-}
-
-static void
-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);
- struct localvar_info **ptr = &localvar_buffer [index];
- struct localvar_info *info = *ptr;
- int wide = TYPE_IS_WIDE (TREE_TYPE (decl));
-
- info->end_label = end_label;
-
- gcc_assert (info->decl == decl);
- if (! really)
- return;
- ptr[0] = NULL;
- if (wide)
- {
- gcc_assert (ptr[1] == (struct localvar_info *) (~0));
- ptr[1] = NULL;
- }
-}
-
-
-#define STACK_TARGET 1
-#define IGNORE_TARGET 2
-
-/* 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. */
-
-static int
-get_access_flags (tree decl)
-{
- int flags = 0;
- int isfield = TREE_CODE (decl) == FIELD_DECL || TREE_CODE (decl) == VAR_DECL;
-
- if (isfield || TREE_CODE (decl) == FUNCTION_DECL)
- {
- if (TREE_PROTECTED (decl))
- flags |= ACC_PROTECTED;
- if (TREE_PRIVATE (decl))
- flags |= ACC_PRIVATE;
- }
- else if (TREE_CODE (decl) == TYPE_DECL)
- {
- if (CLASS_PUBLIC (decl))
- flags |= ACC_PUBLIC;
- if (CLASS_FINAL (decl))
- flags |= ACC_FINAL;
- if (CLASS_SUPER (decl))
- flags |= ACC_SUPER;
- if (CLASS_ABSTRACT (decl))
- flags |= ACC_ABSTRACT;
- if (CLASS_INTERFACE (decl))
- flags |= ACC_INTERFACE;
- if (CLASS_STATIC (decl))
- flags |= ACC_STATIC;
- if (CLASS_PRIVATE (decl))
- flags |= ACC_PRIVATE;
- if (CLASS_PROTECTED (decl))
- flags |= ACC_PROTECTED;
- if (ANONYMOUS_CLASS_P (TREE_TYPE (decl))
- || LOCAL_CLASS_P (TREE_TYPE (decl)))
- flags |= ACC_PRIVATE;
- if (CLASS_STRICTFP (decl))
- flags |= ACC_STRICT;
- }
- else
- gcc_unreachable ();
-
- if (TREE_CODE (decl) == FUNCTION_DECL)
- {
- if (METHOD_PUBLIC (decl))
- flags |= ACC_PUBLIC;
- if (METHOD_FINAL (decl))
- flags |= ACC_FINAL;
- if (METHOD_NATIVE (decl))
- flags |= ACC_NATIVE;
- if (METHOD_STATIC (decl))
- flags |= ACC_STATIC;
- if (METHOD_SYNCHRONIZED (decl))
- flags |= ACC_SYNCHRONIZED;
- if (METHOD_ABSTRACT (decl))
- flags |= ACC_ABSTRACT;
- if (METHOD_STRICTFP (decl))
- flags |= ACC_STRICT;
- }
- if (isfield)
- {
- if (FIELD_PUBLIC (decl))
- flags |= ACC_PUBLIC;
- if (FIELD_FINAL (decl))
- flags |= ACC_FINAL;
- if (FIELD_STATIC (decl))
- flags |= ACC_STATIC;
- if (FIELD_VOLATILE (decl))
- flags |= ACC_VOLATILE;
- if (FIELD_TRANSIENT (decl))
- flags |= ACC_TRANSIENT;
- }
- return flags;
-}
-
-/* Write the list of segments starting at CHUNKS to STREAM. */
-
-static void
-write_chunks (FILE* stream, struct chunk *chunks)
-{
- for (; chunks != NULL; chunks = chunks->next)
- fwrite (chunks->data, chunks->size, 1, stream);
-}
-
-/* Push a 1-word constant in the constant pool at the given INDEX.
- (Caller is responsible for doing NOTE_PUSH.) */
-
-static void
-push_constant1 (HOST_WIDE_INT index, struct jcf_partial *state)
-{
- RESERVE (3);
- if (index < 256)
- {
- OP1 (OPCODE_ldc);
- OP1 (index);
- }
- else
- {
- OP1 (OPCODE_ldc_w);
- OP2 (index);
- }
-}
-
-/* Push a 2-word constant in the constant pool at the given INDEX.
- (Caller is responsible for doing NOTE_PUSH.) */
-
-static void
-push_constant2 (HOST_WIDE_INT index, struct jcf_partial *state)
-{
- RESERVE (3);
- OP1 (OPCODE_ldc2_w);
- OP2 (index);
-}
-
-/* Push 32-bit integer constant on VM stack.
- Caller is responsible for doing NOTE_PUSH. */
-
-static void
-push_int_const (HOST_WIDE_INT i, struct jcf_partial *state)
-{
- RESERVE(3);
- if (i >= -1 && i <= 5)
- OP1(OPCODE_iconst_0 + i);
- else if (i >= -128 && i < 128)
- {
- OP1(OPCODE_bipush);
- OP1(i);
- }
- else if (i >= -32768 && i < 32768)
- {
- OP1(OPCODE_sipush);
- OP2(i);
- }
- else
- {
- i = find_constant1 (&state->cpool, CONSTANT_Integer,
- (jword)(i & 0xFFFFFFFF));
- push_constant1 (i, state);
- }
-}
-
-static int
-find_constant_wide (HOST_WIDE_INT lo, HOST_WIDE_INT hi,
- struct jcf_partial *state)
-{
- unsigned HOST_WIDE_INT w1;
- HOST_WIDE_INT w2;
- lshift_double (lo, hi, -32, 64, &w1, &w2, 1);
- return find_constant2 (&state->cpool, CONSTANT_Long,
- (jword)(w1 & 0xFFFFFFFF), (jword)(lo & 0xFFFFFFFF));
-}
-
-/* Find or allocate a constant pool entry for the given VALUE.
- Return the index in the constant pool. */
-
-static int
-find_constant_index (tree value, struct jcf_partial *state)
-{
- if (TREE_CODE (value) == INTEGER_CST)
- {
- if (TYPE_PRECISION (TREE_TYPE (value)) <= 32)
- return find_constant1 (&state->cpool, CONSTANT_Integer,
- (jword)(TREE_INT_CST_LOW (value) & 0xFFFFFFFF));
- else
- return find_constant_wide (TREE_INT_CST_LOW (value),
- TREE_INT_CST_HIGH (value), state);
- }
- else if (TREE_CODE (value) == REAL_CST)
- {
- long words[2];
-
- /* IEEE NaN can have many values, but the Java VM spec defines a
- canonical NaN. */
- if (flag_emit_class_files
- && REAL_VALUE_ISNAN (TREE_REAL_CST (value)))
- {
- if (TYPE_PRECISION (TREE_TYPE (value)) == 32)
- return find_constant1 (&state->cpool, CONSTANT_Float,
- 0x7fc00000);
- else
- return find_constant2 (&state->cpool, CONSTANT_Double,
- 0x7ff80000, 0x00000000);
- }
-
- real_to_target (words, &TREE_REAL_CST (value),
- TYPE_MODE (TREE_TYPE (value)));
- words[0] &= 0xffffffff;
- words[1] &= 0xffffffff;
-
- if (TYPE_PRECISION (TREE_TYPE (value)) == 32)
- return find_constant1 (&state->cpool, CONSTANT_Float, (jword)words[0]);
- else
- return find_constant2 (&state->cpool, CONSTANT_Double,
- (jword)words[1-FLOAT_WORDS_BIG_ENDIAN],
- (jword)words[FLOAT_WORDS_BIG_ENDIAN]);
- }
- else if (TREE_CODE (value) == STRING_CST)
- return find_string_constant (&state->cpool, value);
-
- else
- gcc_unreachable ();
-}
-
-/* Push 64-bit long constant on VM stack.
- Caller is responsible for doing NOTE_PUSH. */
-
-static void
-push_long_const (HOST_WIDE_INT lo, HOST_WIDE_INT hi, struct jcf_partial *state)
-{
- unsigned HOST_WIDE_INT highpart;
- HOST_WIDE_INT dummy;
- jint lowpart = WORD_TO_INT (lo);
-
- rshift_double (lo, hi, 32, 64, &highpart, &dummy, 1);
-
- if (highpart == 0 && (lowpart == 0 || lowpart == 1))
- {
- RESERVE(1);
- OP1(OPCODE_lconst_0 + lowpart);
- }
- else if ((highpart == 0 && lowpart > 0 && lowpart < 32768)
- || (highpart == (unsigned HOST_WIDE_INT)-1
- && lowpart < 0 && lowpart >= -32768))
- {
- push_int_const (lowpart, state);
- RESERVE (1);
- OP1 (OPCODE_i2l);
- }
- else
- push_constant2 (find_constant_wide (lo, hi, state), state);
-}
-
-static void
-field_op (tree field, int opcode, struct jcf_partial *state)
-{
- int index = find_fieldref_index (&state->cpool, field);
- RESERVE (3);
- OP1 (opcode);
- OP2 (index);
-}
-
-/* Returns an integer in the range 0 (for 'int') through 4 (for object
- reference) to 7 (for 'short') which matches the pattern of how JVM
- opcodes typically depend on the operand type. */
-
-static int
-adjust_typed_op (tree type, int max)
-{
- switch (TREE_CODE (type))
- {
- case POINTER_TYPE:
- case RECORD_TYPE: return 4;
- case BOOLEAN_TYPE:
- return TYPE_PRECISION (type) == 32 || max < 5 ? 0 : 5;
- case INTEGER_TYPE:
- if (type == char_type_node || type == promoted_char_type_node)
- return TYPE_PRECISION (type) == 32 || max < 6 ? 0 : 6;
- switch (TYPE_PRECISION (type))
- {
- case 8: return max < 5 ? 0 : 5;
- case 16: return max < 7 ? 0 : 7;
- case 32: return 0;
- case 64: return 1;
- }
- break;
- case REAL_TYPE:
- switch (TYPE_PRECISION (type))
- {
- case 32: return 2;
- case 64: return 3;
- }
- break;
- default:
- break;
- }
- gcc_unreachable ();
-}
-
-static void
-maybe_wide (int opcode, int index, struct jcf_partial *state)
-{
- if (index >= 256)
- {
- RESERVE (4);
- OP1 (OPCODE_wide);
- OP1 (opcode);
- OP2 (index);
- }
- else
- {
- RESERVE (2);
- OP1 (opcode);
- OP1 (index);
- }
-}
-
-/* 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].) */
-
-static void
-emit_dup (int size, int 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
- gcc_unreachable ();
- OP1 (kind);
- NOTE_PUSH (size);
-}
-
-static void
-emit_pop (int size, struct jcf_partial *state)
-{
- RESERVE (1);
- OP1 (OPCODE_pop - 1 + size);
-}
-
-static void
-emit_iinc (tree var, HOST_WIDE_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 (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);
- 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, state); /* [ilfda]{load,store} */
-}
-
-static void
-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 (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 (enum java_opcode opcode, tree type ATTRIBUTE_UNUSED,
- struct jcf_partial *state)
-{
- RESERVE(1);
- OP1 (opcode);
-}
-
-static void
-emit_binop (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);
-}
-
-static void
-emit_reloc (HOST_WIDE_INT value, int kind,
- struct jcf_block *target, struct jcf_partial *state)
-{
- 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;
- reloc->offset = BUFFER_LENGTH (&state->bytecode);
- reloc->label = target;
- reloc->kind = kind;
- if (kind == 0 || kind == BLOCK_START_RELOC)
- OP4 (value);
- else if (kind != SWITCH_ALIGN_RELOC)
- OP2 (value);
-}
-
-static void
-emit_switch_reloc (struct jcf_block *label, struct jcf_partial *state)
-{
- emit_reloc (RELOCATION_VALUE_0, BLOCK_START_RELOC, label, state);
-}
-
-/* Similar to emit_switch_reloc,
- but re-uses an existing case reloc. */
-
-static void
-emit_case_reloc (struct jcf_relocation *reloc, struct jcf_partial *state)
-{
- struct jcf_block *block = state->last_block;
- reloc->next = block->u.relocations;
- block->u.relocations = reloc;
- reloc->offset = BUFFER_LENGTH (&state->bytecode);
- reloc->kind = BLOCK_START_RELOC;
- OP4 (0);
-}
-
-/* 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 (struct jcf_block *target, int opcode, int inv_opcode,
- struct jcf_partial *state)
-{
- RESERVE(3);
- OP1 (opcode);
- /* value is 1 byte from reloc back to start of instruction. */
- emit_reloc (RELOCATION_VALUE_1, - inv_opcode, target, state);
-}
-
-static void
-emit_goto (struct jcf_block *target, struct jcf_partial *state)
-{
- RESERVE(3);
- OP1 (OPCODE_goto);
- /* Value is 1 byte from reloc back to start of instruction. */
- emit_reloc (RELOCATION_VALUE_1, OPCODE_goto_w, target, state);
-}
-
-static void
-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 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 (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;
- enum java_opcode op, negop;
- bool unordered = 0;
-
- 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);
- gcc_assert (state->code_SP == save_SP_after);
- }
- break;
- case TRUTH_NOT_EXPR:
- generate_bytecode_conditional (TREE_OPERAND (exp, 0), false_label,
- true_label, ! true_branch_first, state);
- 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 UNEQ_EXPR:
- unordered = 1;
- case EQ_EXPR:
- op = OPCODE_if_icmpeq;
- goto compare;
-
- case LTGT_EXPR:
- unordered = 1;
- case NE_EXPR:
- op = OPCODE_if_icmpne;
- goto compare;
-
- case UNLE_EXPR:
- unordered = 1;
- case GT_EXPR:
- op = OPCODE_if_icmpgt;
- goto compare;
-
- case UNGE_EXPR:
- unordered = 1;
- case LT_EXPR:
- op = OPCODE_if_icmplt;
- goto compare;
-
- case UNLT_EXPR:
- unordered = 1;
- case GE_EXPR:
- op = OPCODE_if_icmpge;
- goto compare;
-
- case UNGT_EXPR:
- unordered = 1;
- case LE_EXPR:
- op = OPCODE_if_icmple;
- goto compare;
-
- compare:
- if (unordered)
- {
- /* UNLT_EXPR(a, b) means 'a < b || unordered(a, b)'. This is
- the same as the Java source expression '!(a >= b)', so handle
- it that way. */
- struct jcf_block *tmp = true_label;
- true_label = false_label;
- false_label = tmp;
- true_branch_first = !true_branch_first;
- }
-
- exp0 = TREE_OPERAND (exp, 0);
- exp1 = TREE_OPERAND (exp, 1);
- type = TREE_TYPE (exp0);
- switch (TREE_CODE (type))
- {
- int opf;
- 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:
- gcc_unreachable ();
- }
- if (integer_zerop (exp1) || integer_zerop (exp0))
- {
- generate_bytecode_insns (integer_zerop (exp0) ? exp1 : 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:
- generate_bytecode_insns (exp0, STACK_TARGET, state);
- generate_bytecode_insns (exp1, STACK_TARGET, state);
- if (op == OPCODE_if_icmplt || op == OPCODE_if_icmple)
- opf = OPCODE_fcmpg;
- else
- opf = OPCODE_fcmpl;
- if (TYPE_PRECISION (type) > 32)
- {
- opf += 2;
- NOTE_POP (4);
- }
- else
- NOTE_POP (2);
- RESERVE (1);
- OP1 (opf);
- goto compare_1;
- 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;
- }
- /* FALLTHROUGH */
- 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;
- default:
- 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;
- }
- gcc_assert (save_SP == state->code_SP);
-}
-
-/* Call pending cleanups i.e. those for surrounding TRY_FINALLY_EXPRs.
- but only as far out as LIMIT (since we are about to jump to the
- emit label that is LIMIT). */
-
-static void
-call_cleanups (struct jcf_block *limit, struct jcf_partial *state)
-{
- struct jcf_block *block = state->labeled_blocks;
- for (; block != limit; block = block->next)
- {
- if (block->pc == PENDING_CLEANUP_PC)
- emit_jsr (block, state);
- }
-}
-
-static void
-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;
- int op;
- again:
- if (exp != NULL)
- {
- switch (TREE_CODE (exp))
- {
- case COMPOUND_EXPR:
- generate_bytecode_insns (TREE_OPERAND (exp, 0), IGNORE_TARGET,
- state);
- exp = TREE_OPERAND (exp, 1);
- goto again;
- case COND_EXPR:
- {
- struct jcf_block *then_label = gen_jcf_label (state);
- struct jcf_block *else_label = gen_jcf_label (state);
- generate_bytecode_conditional (TREE_OPERAND (exp, 0),
- then_label, else_label, 1, state);
- define_jcf_label (then_label, state);
- generate_bytecode_return (TREE_OPERAND (exp, 1), state);
- define_jcf_label (else_label, state);
- generate_bytecode_return (TREE_OPERAND (exp, 2), state);
- }
- return;
- default:
- generate_bytecode_insns (exp,
- returns_void ? IGNORE_TARGET
- : STACK_TARGET, state);
- }
- }
- if (returns_void)
- {
- op = OPCODE_return;
- call_cleanups (NULL, state);
- }
- else
- {
- op = OPCODE_ireturn + adjust_typed_op (return_type, 4);
- if (state->num_finalizers > 0)
- {
- if (state->return_value_decl == NULL_TREE)
- {
- state->return_value_decl
- = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (exp));
- localvar_alloc (state->return_value_decl, state);
- }
- emit_store (state->return_value_decl, state);
- call_cleanups (NULL, state);
- emit_load (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
- the greatest solution, but it is at least simple and safe. */
- }
- }
- RESERVE (1);
- OP1 (op);
-}
-
-/* Generate bytecode for sub-expression EXP of METHOD.
- TARGET is one of STACK_TARGET or IGNORE_TARGET. */
-
-static void
-generate_bytecode_insns (tree exp, int target, struct jcf_partial *state)
-{
- tree type, arg;
- 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:
- if (BLOCK_EXPR_BODY (exp))
- {
- 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);
- localvar_alloc (local, state);
- local = next;
- }
- /* Avoid deep recursion for long blocks. */
- while (TREE_CODE (body) == COMPOUND_EXPR)
- {
- generate_bytecode_insns (TREE_OPERAND (body, 0), 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);
- maybe_free_localvar (local, state, state->num_jsrs <= jsrs);
- local = next;
- }
- }
- break;
- case COMPOUND_EXPR:
- generate_bytecode_insns (TREE_OPERAND (exp, 0), IGNORE_TARGET, state);
- /* Normally the first operand to a COMPOUND_EXPR must complete
- normally. However, in the special case of a do-while
- statement this is not necessarily the case. */
- if (CAN_COMPLETE_NORMALLY (TREE_OPERAND (exp, 0)))
- generate_bytecode_insns (TREE_OPERAND (exp, 1), target, state);
- break;
- case EXPR_WITH_FILE_LOCATION:
- {
- location_t saved_location = input_location;
- tree body = EXPR_WFL_NODE (exp);
- if (IS_EMPTY_STMT (body))
- break;
-#ifdef USE_MAPPED_LOCATION
- input_location = EXPR_LOCATION (exp);
-#else
- input_filename = EXPR_WFL_FILENAME (exp);
- input_line = EXPR_WFL_LINENO (exp);
-#endif
- if (EXPR_WFL_EMIT_LINE_NOTE (exp) && input_line > 0
- && debug_info_level > DINFO_LEVEL_NONE)
- put_linenumber (input_line, state);
- generate_bytecode_insns (body, target, state);
- input_location = saved_location;
- }
- break;
- case INTEGER_CST:
- if (target == IGNORE_TARGET) ; /* do nothing */
- else if (TREE_CODE (type) == POINTER_TYPE)
- {
- gcc_assert (integer_zerop (exp));
- RESERVE(1);
- OP1 (OPCODE_aconst_null);
- NOTE_PUSH (1);
- }
- else if (TYPE_PRECISION (type) <= 32)
- {
- 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),
- state);
- NOTE_PUSH (2);
- }
- break;
- case REAL_CST:
- {
- int prec = TYPE_PRECISION (type) >> 5;
- RESERVE(1);
- if (real_zerop (exp) && ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (exp)))
- OP1 (prec == 1 ? OPCODE_fconst_0 : OPCODE_dconst_0);
- else if (real_onep (exp))
- OP1 (prec == 1 ? OPCODE_fconst_1 : OPCODE_dconst_1);
- 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
- {
- offset = find_constant_index (exp, state);
- if (prec == 1)
- push_constant1 (offset, state);
- else
- push_constant2 (offset, state);
- }
- NOTE_PUSH (prec);
- }
- break;
- case STRING_CST:
- push_constant1 (find_string_constant (&state->cpool, exp), state);
- NOTE_PUSH (1);
- break;
- case VAR_DECL:
- if (TREE_STATIC (exp))
- {
- field_op (exp, OPCODE_getstatic, state);
- NOTE_PUSH (TYPE_IS_WIDE (TREE_TYPE (exp)) ? 2 : 1);
- break;
- }
- /* ... fall through ... */
- case PARM_DECL:
- emit_load (exp, state);
- break;
- case NON_LVALUE_EXPR:
- case INDIRECT_REF:
- generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state);
- break;
- case ARRAY_REF:
- 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, 7);
- RESERVE(1);
- OP1 (jopcode);
- if (! TYPE_IS_WIDE (type))
- NOTE_POP (1);
- }
- break;
- case COMPONENT_REF:
- {
- tree obj = TREE_OPERAND (exp, 0);
- tree field = TREE_OPERAND (exp, 1);
- int is_static = FIELD_STATIC (field);
- generate_bytecode_insns (obj,
- is_static ? IGNORE_TARGET : target, state);
- if (target != IGNORE_TARGET)
- {
- if (DECL_NAME (field) == length_identifier_node && !is_static
- && TYPE_ARRAY_P (TREE_TYPE (obj)))
- {
- RESERVE (1);
- OP1 (OPCODE_arraylength);
- }
- else
- {
- 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:
- case UNLT_EXPR:
- case UNLE_EXPR:
- case UNGT_EXPR:
- case UNGE_EXPR:
- case UNEQ_EXPR:
- case LTGT_EXPR:
- {
- struct jcf_block *then_label = gen_jcf_label (state);
- struct jcf_block *else_label = gen_jcf_label (state);
- 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);
- if (CAN_COMPLETE_NORMALLY (TREE_OPERAND (exp, 1))
- /* Not all expressions have CAN_COMPLETE_NORMALLY set properly. */
- || TREE_CODE (TREE_TYPE (exp)) != VOID_TYPE)
- 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);
- /* COND_EXPR can be used in a binop. The stack must be adjusted. */
- if (TREE_TYPE (exp) != void_type_node)
- NOTE_POP (TYPE_IS_WIDE (TREE_TYPE (exp)) ? 2 : 1);
- }
- break;
- case CASE_EXPR:
- {
- struct jcf_switch_state *sw_state = state->sw_state;
- 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);
- reloc->offset = case_value;
- reloc->next = sw_state->cases;
- sw_state->cases = reloc;
- if (sw_state->num_cases == 0)
- {
- sw_state->min_case = case_value;
- sw_state->max_case = case_value;
- }
- else
- {
- if (case_value < sw_state->min_case)
- sw_state->min_case = case_value;
- if (case_value > sw_state->max_case)
- sw_state->max_case = case_value;
- }
- sw_state->num_cases++;
- }
- break;
- case DEFAULT_EXPR:
- state->sw_state->default_label = get_jcf_label_here (state);
- break;
-
- case SWITCH_EXPR:
- {
- /* The SWITCH_EXPR has three parts, generated in the following order:
- 1. the switch_expression (the value used to select the correct case);
- 2. the switch_body;
- 3. the switch_instruction (the tableswitch/loopupswitch instruction.).
- After code generation, we will re-order them in the order 1, 3, 2.
- This is to avoid any extra GOTOs. */
- struct jcf_switch_state sw_state;
- struct jcf_block *expression_last; /* Last block of the switch_expression. */
- struct jcf_block *body_last; /* Last block of the switch_body. */
- struct jcf_block *switch_instruction; /* First block of switch_instruction. */
- struct jcf_block *instruction_last; /* Last block of the switch_instruction. */
- struct jcf_block *body_block;
- int switch_length;
- sw_state.prev = state->sw_state;
- state->sw_state = &sw_state;
- sw_state.cases = NULL;
- sw_state.num_cases = 0;
- sw_state.default_label = NULL;
- generate_bytecode_insns (TREE_OPERAND (exp, 0), STACK_TARGET, state);
- expression_last = state->last_block;
- /* Force a new block here. */
- body_block = gen_jcf_label (state);
- define_jcf_label (body_block, state);
- generate_bytecode_insns (TREE_OPERAND (exp, 1), IGNORE_TARGET, state);
- body_last = state->last_block;
-
- switch_instruction = gen_jcf_label (state);
- define_jcf_label (switch_instruction, state);
- if (sw_state.default_label == NULL)
- sw_state.default_label = gen_jcf_label (state);
-
- if (sw_state.num_cases <= 1)
- {
- if (sw_state.num_cases == 0)
- {
- emit_pop (1, state);
- NOTE_POP (1);
- }
- else
- {
- push_int_const (sw_state.cases->offset, state);
- NOTE_PUSH (1);
- emit_if (sw_state.cases->label,
- OPCODE_if_icmpeq, OPCODE_if_icmpne, state);
- }
- emit_goto (sw_state.default_label, state);
- }
- else
- {
- HOST_WIDE_INT i;
- unsigned HOST_WIDE_INT delta;
- /* Copy the chain of relocs into a sorted array. */
- struct jcf_relocation **relocs
- = XNEWVEC (struct jcf_relocation *, sw_state.num_cases);
- /* The relocs arrays is a buffer with a gap.
- The assumption is that cases will normally come in "runs". */
- int gap_start = 0;
- int gap_end = sw_state.num_cases;
- struct jcf_relocation *reloc;
- for (reloc = sw_state.cases; reloc != NULL; reloc = reloc->next)
- {
- HOST_WIDE_INT case_value = reloc->offset;
- while (gap_end < sw_state.num_cases)
- {
- struct jcf_relocation *end = relocs[gap_end];
- if (case_value <= end->offset)
- break;
- relocs[gap_start++] = end;
- gap_end++;
- }
- while (gap_start > 0)
- {
- struct jcf_relocation *before = relocs[gap_start-1];
- if (case_value >= before->offset)
- break;
- relocs[--gap_end] = before;
- gap_start--;
- }
- relocs[gap_start++] = reloc;
- /* Note we don't check for duplicates. This is
- handled by the parser. */
- }
-
- /* We could have DELTA < 0 if sw_state.min_case is
- something like Integer.MIN_VALUE. That is why delta is
- unsigned. */
- delta = sw_state.max_case - sw_state.min_case;
- 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));
- OP1 (OPCODE_tableswitch);
- emit_reloc (RELOCATION_VALUE_0,
- SWITCH_ALIGN_RELOC, NULL, state);
- emit_switch_reloc (sw_state.default_label, state);
- OP4 (sw_state.min_case);
- OP4 (sw_state.max_case);
- for (i = sw_state.min_case; ; )
- {
- reloc = relocs[index];
- if (i == reloc->offset)
- {
- emit_case_reloc (reloc, state);
- if (i == sw_state.max_case)
- break;
- index++;
- }
- else
- emit_switch_reloc (sw_state.default_label, state);
- i++;
- }
- }
- else
- { /* Use lookupswitch. */
- RESERVE(9 + 8 * sw_state.num_cases);
- OP1 (OPCODE_lookupswitch);
- emit_reloc (RELOCATION_VALUE_0,
- SWITCH_ALIGN_RELOC, NULL, state);
- emit_switch_reloc (sw_state.default_label, state);
- OP4 (sw_state.num_cases);
- for (i = 0; i < sw_state.num_cases; i++)
- {
- struct jcf_relocation *reloc = relocs[i];
- OP4 (reloc->offset);
- emit_case_reloc (reloc, state);
- }
- }
- free (relocs);
- }
-
- instruction_last = state->last_block;
- if (sw_state.default_label->pc < 0)
- define_jcf_label (sw_state.default_label, state);
- else /* Force a new block. */
- sw_state.default_label = get_jcf_label_here (state);
- /* Now re-arrange the blocks so the switch_instruction
- comes before the switch_body. */
- switch_length = state->code_length - switch_instruction->pc;
- switch_instruction->pc = body_block->pc;
- instruction_last->next = body_block;
- instruction_last->v.chunk->next = body_block->v.chunk;
- expression_last->next = switch_instruction;
- expression_last->v.chunk->next = switch_instruction->v.chunk;
- body_last->next = sw_state.default_label;
- body_last->v.chunk->next = NULL;
- state->chunk = body_last->v.chunk;
- for (; body_block != sw_state.default_label; body_block = body_block->next)
- body_block->pc += switch_length;
-
- state->sw_state = sw_state.prev;
- break;
- }
-
- case RETURN_EXPR:
- exp = TREE_OPERAND (exp, 0);
- if (exp == NULL_TREE)
- exp = build_java_empty_stmt ();
- else if (TREE_CODE (exp) != MODIFY_EXPR)
- gcc_unreachable ();
- else
- exp = TREE_OPERAND (exp, 1);
- generate_bytecode_return (exp, state);
- break;
- case LABELED_BLOCK_EXPR:
- {
- struct jcf_block *end_label = gen_jcf_label (state);
- end_label->next = state->labeled_blocks;
- state->labeled_blocks = end_label;
- end_label->pc = PENDING_EXIT_PC;
- end_label->u.labeled_block = exp;
- if (LABELED_BLOCK_BODY (exp))
- generate_bytecode_insns (LABELED_BLOCK_BODY (exp), target, state);
- gcc_assert (state->labeled_blocks == end_label);
- 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 (body) == COMPOUND_EXPR
- && TREE_CODE (TREE_OPERAND (body, 0)) == EXIT_EXPR)
- {
- /* 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
- {
- struct jcf_block *head_label = get_jcf_label_here (state);
- generate_bytecode_insns (body, IGNORE_TARGET, state);
- if (CAN_COMPLETE_NORMALLY (body))
- emit_goto (head_label, state);
- }
- }
- 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;
- while (label->u.labeled_block != EXIT_BLOCK_LABELED_BLOCK (exp))
- label = label->next;
- call_cleanups (label, state);
- 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:
-
- arg = TREE_OPERAND (exp, 1);
- 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 && ! post_op)
- emit_load (exp, state);
- 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_getfield, state);
- NOTE_PUSH (size-1);
- /* 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), 7);
- 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
- gcc_unreachable ();
-
- 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. */
- generate_bytecode_insns (arg, STACK_TARGET, state);
- emit_binop ((value >= 0 ? OPCODE_iadd : OPCODE_isub)
- + adjust_typed_op (type, 3),
- type, state);
- if (target != IGNORE_TARGET && ! post_op)
- emit_dup (size, offset, state);
- /* Stack, if ARRAY_REF: ..., [result, ] array, index, newvalue. */
- /* Stack, if COMPONENT_REF: ..., [result, ] objectref, newvalue. */
- /* Stack, otherwise: ..., [result, ] newvalue. */
- goto finish_assignment;
-
- case MODIFY_EXPR:
- {
- tree lhs = TREE_OPERAND (exp, 0);
- tree rhs = TREE_OPERAND (exp, 1);
- int offset = 0;
-
- /* 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))
- {
- 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)
- {
- min_value++;
- max_value++;
- }
- else if (arg1 == lhs)
- {
- 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))
- {
- if (TREE_CODE (rhs) == MINUS_EXPR)
- value = -value;
- emit_iinc (lhs, value, state);
- if (target != IGNORE_TARGET)
- emit_load (lhs, state);
- break;
- }
- }
- }
-
- if (TREE_CODE (lhs) == COMPONENT_REF)
- {
- generate_bytecode_insns (TREE_OPERAND (lhs, 0),
- STACK_TARGET, state);
- offset = 1;
- }
- else if (TREE_CODE (lhs) == ARRAY_REF)
- {
- generate_bytecode_insns (TREE_OPERAND(lhs, 0),
- STACK_TARGET, state);
- generate_bytecode_insns (TREE_OPERAND(lhs, 1),
- STACK_TARGET, state);
- offset = 2;
- }
- else
- offset = 0;
-
- /* If the rhs is a binary expression and the left operand is
- `==' to the lhs then we have an OP= expression. In this
- case we must do some special processing. */
- if (BINARY_CLASS_P (rhs) && lhs == TREE_OPERAND (rhs, 0))
- {
- if (TREE_CODE (lhs) == COMPONENT_REF)
- {
- tree field = TREE_OPERAND (lhs, 1);
- if (! FIELD_STATIC (field))
- {
- /* Duplicate the object reference so we can get
- the field. */
- emit_dup (TYPE_IS_WIDE (field) ? 2 : 1, 0, state);
- NOTE_POP (1);
- }
- field_op (field, (FIELD_STATIC (field)
- ? OPCODE_getstatic
- : OPCODE_getfield),
- state);
-
- NOTE_PUSH (TYPE_IS_WIDE (TREE_TYPE (field)) ? 2 : 1);
- }
- else if (TREE_CODE (lhs) == VAR_DECL
- || TREE_CODE (lhs) == PARM_DECL)
- {
- if (FIELD_STATIC (lhs))
- {
- field_op (lhs, OPCODE_getstatic, state);
- NOTE_PUSH (TYPE_IS_WIDE (TREE_TYPE (lhs)) ? 2 : 1);
- }
- else
- emit_load (lhs, state);
- }
- else if (TREE_CODE (lhs) == ARRAY_REF)
- {
- /* Duplicate the array and index, which are on the
- stack, so that we can load the old value. */
- emit_dup (2, 0, state);
- NOTE_POP (2);
- jopcode = OPCODE_iaload + adjust_typed_op (TREE_TYPE (lhs), 7);
- RESERVE (1);
- OP1 (jopcode);
- NOTE_PUSH (TYPE_IS_WIDE (TREE_TYPE (lhs)) ? 2 : 1);
- }
- else
- gcc_unreachable ();
-
- /* This function correctly handles the case where the LHS
- of a binary expression is NULL_TREE. */
- rhs = build2 (TREE_CODE (rhs), TREE_TYPE (rhs),
- NULL_TREE, TREE_OPERAND (rhs, 1));
- }
-
- generate_bytecode_insns (rhs, STACK_TARGET, state);
- if (target != IGNORE_TARGET)
- emit_dup (TYPE_IS_WIDE (type) ? 2 : 1 , offset, state);
- exp = lhs;
- }
- /* FALLTHROUGH */
-
- 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_POP (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_POP (TYPE_IS_WIDE (TREE_TYPE (exp)) ? 2 : 1);
- }
- else
- emit_store (exp, state);
- }
- else if (TREE_CODE (exp) == ARRAY_REF)
- {
- jopcode = OPCODE_iastore + adjust_typed_op (TREE_TYPE (exp), 7);
- RESERVE (1);
- OP1 (jopcode);
- NOTE_POP (TYPE_IS_WIDE (TREE_TYPE (exp)) ? 4 : 3);
- }
- else
- gcc_unreachable ();
- break;
- case PLUS_EXPR:
- jopcode = OPCODE_iadd;
- goto binop;
- case MINUS_EXPR:
- jopcode = OPCODE_isub;
- goto binop;
- case MULT_EXPR:
- jopcode = OPCODE_imul;
- goto binop;
- case TRUNC_DIV_EXPR:
- case RDIV_EXPR:
- jopcode = OPCODE_idiv;
- goto binop;
- case TRUNC_MOD_EXPR:
- jopcode = OPCODE_irem;
- goto binop;
- case LSHIFT_EXPR: jopcode = OPCODE_ishl; goto binop;
- case RSHIFT_EXPR:
- jopcode = TYPE_UNSIGNED (type) ? OPCODE_iushr : OPCODE_ishr;
- goto binop;
- case URSHIFT_EXPR: jopcode = OPCODE_iushr; goto binop;
- case TRUTH_AND_EXPR:
- case BIT_AND_EXPR: jopcode = OPCODE_iand; goto binop;
- case TRUTH_OR_EXPR:
- case BIT_IOR_EXPR: jopcode = OPCODE_ior; goto binop;
- case TRUTH_XOR_EXPR:
- case BIT_XOR_EXPR: jopcode = OPCODE_ixor; goto binop;
- binop:
- {
- tree arg0 = TREE_OPERAND (exp, 0);
- tree arg1 = TREE_OPERAND (exp, 1);
- jopcode += adjust_typed_op (type, 3);
- if (arg0 != NULL_TREE && operand_equal_p (arg0, arg1, 0))
- {
- /* fold may (e.g) convert 2*x to x+x. */
- generate_bytecode_insns (arg0, target, state);
- emit_dup (TYPE_PRECISION (TREE_TYPE (arg0)) > 32 ? 2 : 1, 0, state);
- }
- else
- {
- /* ARG0 will be NULL_TREE if we're handling an `OP='
- expression. In this case the stack already holds the
- LHS. See the MODIFY_EXPR case. */
- if (arg0 != NULL_TREE)
- generate_bytecode_insns (arg0, target, state);
- if (jopcode >= OPCODE_lshl && jopcode <= OPCODE_lushr)
- arg1 = convert (int_type_node, arg1);
- generate_bytecode_insns (arg1, target, state);
- }
- /* For most binary operations, both operands and the result have the
- same type. Shift operations are different. Using arg1's type
- gets us the correct SP adjustment in all cases. */
- if (target == STACK_TARGET)
- emit_binop (jopcode, TREE_TYPE (arg1), state);
- break;
- }
- case TRUTH_NOT_EXPR:
- case BIT_NOT_EXPR:
- generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state);
- if (target == STACK_TARGET)
- {
- int is_long = TYPE_PRECISION (TREE_TYPE (exp)) > 32;
- push_int_const (TREE_CODE (exp) == BIT_NOT_EXPR ? -1 : 1, state);
- RESERVE (2);
- if (is_long)
- OP1 (OPCODE_i2l);
- NOTE_PUSH (1 + is_long);
- OP1 (OPCODE_ixor + is_long);
- NOTE_POP (1 + is_long);
- }
- break;
- case NEGATE_EXPR:
- jopcode = OPCODE_ineg;
- jopcode += adjust_typed_op (type, 3);
- generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state);
- if (target == STACK_TARGET)
- emit_unop (jopcode, type, state);
- break;
- case INSTANCEOF_EXPR:
- {
- int index = find_class_constant (&state->cpool, TREE_OPERAND (exp, 1));
- generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state);
- RESERVE (3);
- OP1 (OPCODE_instanceof);
- OP2 (index);
- }
- break;
- case SAVE_EXPR:
- /* The first time through, the argument of the SAVE_EXPR will be
- something complex. Evaluate it, and replace the argument with
- a VAR_DECL that holds the result. */
- arg = TREE_OPERAND (exp, 0);
- if (TREE_CODE (arg) != VAR_DECL || DECL_NAME (arg))
- {
- tree type = TREE_TYPE (exp);
- tree decl = build_decl (VAR_DECL, NULL_TREE, type);
- generate_bytecode_insns (arg, STACK_TARGET, state);
- localvar_alloc (decl, state);
- TREE_OPERAND (exp, 0) = decl;
- emit_dup (TYPE_IS_WIDE (type) ? 2 : 1, 0, state);
- emit_store (decl, state);
- }
- else
- {
- emit_load (arg, state);
- }
- break;
- case CONVERT_EXPR:
- case NOP_EXPR:
- case FLOAT_EXPR:
- case FIX_TRUNC_EXPR:
- {
- tree src = TREE_OPERAND (exp, 0);
- tree src_type = TREE_TYPE (src);
- tree dst_type = TREE_TYPE (exp);
- generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state);
- if (target == IGNORE_TARGET || src_type == dst_type)
- break;
- if (TREE_CODE (dst_type) == POINTER_TYPE)
- {
- if (TREE_CODE (exp) == CONVERT_EXPR)
- {
- int index = find_class_constant (&state->cpool,
- TREE_TYPE (dst_type));
- RESERVE (3);
- OP1 (OPCODE_checkcast);
- OP2 (index);
- }
- }
- else /* Convert numeric types. */
- {
- int src_prec = TYPE_PRECISION (src_type);
- int dst_prec = TYPE_PRECISION (dst_type);
- int wide_src = src_prec > 32;
- int wide_dst = dst_prec > 32;
- if (TREE_CODE (dst_type) == REAL_TYPE)
- {
- NOTE_POP (1 + wide_src);
- RESERVE (1);
- if (TREE_CODE (src_type) == REAL_TYPE)
- OP1 (wide_dst ? OPCODE_f2d : OPCODE_d2f);
- else if (src_prec == 64)
- OP1 (OPCODE_l2f + wide_dst);
- else
- OP1 (OPCODE_i2f + wide_dst);
- NOTE_PUSH (1 + wide_dst);
- }
- /* Convert to integral type (but ignore non-widening
- and non-narrowing integer type conversions). */
- else if (TREE_CODE (src_type) == REAL_TYPE
- || src_prec != dst_prec)
- {
- NOTE_POP (1 + wide_src);
- RESERVE (1);
- if (TREE_CODE (src_type) == REAL_TYPE)
- OP1 (OPCODE_f2i + wide_dst + 3 * wide_src);
- else if (wide_dst)
- OP1 (OPCODE_i2l);
- else if (wide_src)
- OP1 (OPCODE_l2i);
- if (dst_prec < 32)
- {
- RESERVE (1);
- /* Already converted to int, if needed. */
- if (dst_prec <= 8)
- OP1 (OPCODE_i2b);
- else if (TYPE_UNSIGNED (dst_type))
- OP1 (OPCODE_i2c);
- else
- OP1 (OPCODE_i2s);
- }
- NOTE_PUSH (1 + wide_dst);
- }
- }
- }
- break;
-
- case TRY_EXPR:
- {
- tree try_clause = TREE_OPERAND (exp, 0);
- struct jcf_block *start_label = get_jcf_label_here (state);
- struct jcf_block *end_label; /* End of try clause. */
- struct jcf_block *finished_label = gen_jcf_label (state);
- tree clause = TREE_OPERAND (exp, 1);
- gcc_assert (target == IGNORE_TARGET);
- generate_bytecode_insns (try_clause, IGNORE_TARGET, state);
- end_label = get_jcf_label_here (state);
- if (end_label == start_label)
- break;
- if (CAN_COMPLETE_NORMALLY (try_clause))
- emit_goto (finished_label, state);
- while (clause != NULL_TREE)
- {
- tree catch_clause = TREE_OPERAND (clause, 0);
- tree exception_decl = BLOCK_EXPR_DECLS (catch_clause);
- struct jcf_handler *handler = alloc_handler (start_label,
- end_label, state);
- if (exception_decl == NULL_TREE)
- handler->type = NULL_TREE;
- else
- handler->type = TREE_TYPE (TREE_TYPE (exception_decl));
- generate_bytecode_insns (catch_clause, IGNORE_TARGET, state);
- clause = TREE_CHAIN (clause);
- if (CAN_COMPLETE_NORMALLY (catch_clause) && clause != NULL_TREE)
- emit_goto (finished_label, state);
- }
- define_jcf_label (finished_label, state);
- }
- break;
-
- case TRY_FINALLY_EXPR:
- {
- struct jcf_block *finished_label = NULL;
- struct jcf_block *finally_label, *start_label, *end_label;
- struct jcf_handler *handler;
- tree try_block = TREE_OPERAND (exp, 0);
- tree finally = TREE_OPERAND (exp, 1);
- tree return_link = NULL_TREE, exception_decl = NULL_TREE;
-
- tree exception_type;
-
- finally_label = gen_jcf_label (state);
- start_label = get_jcf_label_here (state);
- /* If the `finally' clause can complete normally, we emit it
- as a subroutine and let the other clauses call it via
- `jsr'. If it can't complete normally, then we simply emit
- `goto's directly to it. */
- if (CAN_COMPLETE_NORMALLY (finally))
- {
- finally_label->pc = PENDING_CLEANUP_PC;
- finally_label->next = state->labeled_blocks;
- state->labeled_blocks = finally_label;
- state->num_finalizers++;
- }
-
- generate_bytecode_insns (try_block, target, state);
-
- if (CAN_COMPLETE_NORMALLY (finally))
- {
- gcc_assert (state->labeled_blocks == finally_label);
- state->labeled_blocks = finally_label->next;
- }
- end_label = get_jcf_label_here (state);
-
- if (end_label == start_label)
- {
- state->num_finalizers--;
- define_jcf_label (finally_label, state);
- generate_bytecode_insns (finally, IGNORE_TARGET, state);
- break;
- }
-
- if (CAN_COMPLETE_NORMALLY (finally))
- {
- return_link = build_decl (VAR_DECL, NULL_TREE,
- return_address_type_node);
- finished_label = gen_jcf_label (state);
- }
-
- if (CAN_COMPLETE_NORMALLY (try_block))
- {
- if (CAN_COMPLETE_NORMALLY (finally))
- {
- emit_jsr (finally_label, state);
- emit_goto (finished_label, state);
- }
- else
- emit_goto (finally_label, state);
- }
-
- /* Handle exceptions. */
-
- exception_type = build_pointer_type (throwable_type_node);
- if (CAN_COMPLETE_NORMALLY (finally))
- {
- /* We're going to generate a subroutine, so we'll need to
- save and restore the exception around the `jsr'. */
- exception_decl = build_decl (VAR_DECL, NULL_TREE, exception_type);
- localvar_alloc (return_link, state);
- }
- handler = alloc_handler (start_label, end_label, state);
- handler->type = NULL_TREE;
- if (CAN_COMPLETE_NORMALLY (finally))
- {
- localvar_alloc (exception_decl, state);
- NOTE_PUSH (1);
- emit_store (exception_decl, state);
- emit_jsr (finally_label, state);
- emit_load (exception_decl, state);
- RESERVE (1);
- OP1 (OPCODE_athrow);
- NOTE_POP (1);
- }
- else
- {
- /* We're not generating a subroutine. In this case we can
- simply have the exception handler pop the exception and
- then fall through to the `finally' block. */
- NOTE_PUSH (1);
- emit_pop (1, state);
- NOTE_POP (1);
- }
-
- /* The finally block. If we're generating a subroutine, first
- save return PC into return_link. Otherwise, just generate
- the code for the `finally' block. */
- define_jcf_label (finally_label, state);
- if (CAN_COMPLETE_NORMALLY (finally))
- {
- NOTE_PUSH (1);
- emit_store (return_link, state);
- }
-
- generate_bytecode_insns (finally, IGNORE_TARGET, state);
- if (CAN_COMPLETE_NORMALLY (finally))
- {
- maybe_wide (OPCODE_ret, DECL_LOCAL_INDEX (return_link), state);
- maybe_free_localvar (exception_decl, state, 1);
- maybe_free_localvar (return_link, state, 1);
- define_jcf_label (finished_label, state);
- }
- }
- break;
- case THROW_EXPR:
- generate_bytecode_insns (TREE_OPERAND (exp, 0), STACK_TARGET, state);
- RESERVE (1);
- OP1 (OPCODE_athrow);
- break;
- case NEW_ARRAY_INIT:
- {
- VEC(constructor_elt,gc) *v = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0));
- tree array_type = TREE_TYPE (TREE_TYPE (exp));
- tree element_type = TYPE_ARRAY_ELEMENT (array_type);
- unsigned HOST_WIDE_INT idx;
- tree value;
- HOST_WIDE_INT length = java_array_type_length (array_type);
- if (target == IGNORE_TARGET)
- {
- FOR_EACH_CONSTRUCTOR_VALUE (v, idx, value)
- generate_bytecode_insns (value, target, state);
- break;
- }
- push_int_const (length, state);
- NOTE_PUSH (1);
- RESERVE (3);
- if (JPRIMITIVE_TYPE_P (element_type))
- {
- int atype = encode_newarray_type (element_type);
- OP1 (OPCODE_newarray);
- OP1 (atype);
- }
- else
- {
- int index = find_class_constant (&state->cpool,
- TREE_TYPE (element_type));
- OP1 (OPCODE_anewarray);
- OP2 (index);
- }
- offset = 0;
- jopcode = OPCODE_iastore + adjust_typed_op (element_type, 7);
- FOR_EACH_CONSTRUCTOR_VALUE (v, idx, value)
- {
- int save_SP = state->code_SP;
- emit_dup (1, 0, state);
- push_int_const (offset, state);
- NOTE_PUSH (1);
- generate_bytecode_insns (value, STACK_TARGET, state);
- RESERVE (1);
- OP1 (jopcode);
- state->code_SP = save_SP;
- offset++;
- }
- }
- break;
- 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;
- gcc_assert (! TREE_SIDE_EFFECTS (op0) && ! TREE_SIDE_EFFECTS (op1));
- x = build3 (COND_EXPR, TREE_TYPE (exp),
- build2 (code, boolean_type_node, op0, op1),
- op0, op1);
- generate_bytecode_insns (x, target, state);
- break;
- }
- case NEW_CLASS_EXPR:
- {
- tree class = TREE_TYPE (TREE_TYPE (exp));
- int need_result = target != IGNORE_TARGET;
- int index = find_class_constant (&state->cpool, class);
- RESERVE (4);
- OP1 (OPCODE_new);
- OP2 (index);
- if (need_result)
- OP1 (OPCODE_dup);
- NOTE_PUSH (1 + need_result);
- }
- /* ... fall though ... */
- case CALL_EXPR:
- {
- tree f = TREE_OPERAND (exp, 0);
- tree x = TREE_OPERAND (exp, 1);
- int save_SP = state->code_SP;
- int nargs;
- if (TREE_CODE (f) == ADDR_EXPR)
- f = TREE_OPERAND (f, 0);
- if (f == soft_newarray_node)
- {
- int type_code = TREE_INT_CST_LOW (TREE_VALUE (x));
- generate_bytecode_insns (TREE_VALUE (TREE_CHAIN (x)),
- STACK_TARGET, state);
- RESERVE (2);
- OP1 (OPCODE_newarray);
- OP1 (type_code);
- break;
- }
- else if (f == soft_multianewarray_node)
- {
- int ndims;
- int idim;
- int index = find_class_constant (&state->cpool,
- TREE_TYPE (TREE_TYPE (exp)));
- x = TREE_CHAIN (x); /* Skip class argument. */
- ndims = TREE_INT_CST_LOW (TREE_VALUE (x));
- for (idim = ndims; --idim >= 0; )
- {
- x = TREE_CHAIN (x);
- generate_bytecode_insns (TREE_VALUE (x), STACK_TARGET, state);
- }
- RESERVE (4);
- OP1 (OPCODE_multianewarray);
- OP2 (index);
- OP1 (ndims);
- NOTE_POP (ndims - 1);
- break;
- }
- else if (f == soft_anewarray_node)
- {
- tree cl = TYPE_ARRAY_ELEMENT (TREE_TYPE (TREE_TYPE (exp)));
- int index = find_class_constant (&state->cpool, TREE_TYPE (cl));
- generate_bytecode_insns (TREE_VALUE (x), STACK_TARGET, state);
- RESERVE (3);
- OP1 (OPCODE_anewarray);
- OP2 (index);
- break;
- }
- else if (f == soft_monitorenter_node
- || f == soft_monitorexit_node
- || f == throw_node)
- {
- if (f == soft_monitorenter_node)
- op = OPCODE_monitorenter;
- else if (f == soft_monitorexit_node)
- op = OPCODE_monitorexit;
- else
- op = OPCODE_athrow;
- generate_bytecode_insns (TREE_VALUE (x), STACK_TARGET, state);
- RESERVE (1);
- OP1 (op);
- NOTE_POP (1);
- break;
- }
- for ( ; x != NULL_TREE; x = TREE_CHAIN (x))
- {
- generate_bytecode_insns (TREE_VALUE (x), STACK_TARGET, state);
- }
- nargs = state->code_SP - save_SP;
- state->code_SP = save_SP;
- if (f == soft_fmod_node)
- {
- RESERVE (1);
- OP1 (OPCODE_drem);
- NOTE_PUSH (2);
- break;
- }
- if (TREE_CODE (exp) == NEW_CLASS_EXPR)
- NOTE_POP (1); /* Pop implicit this. */
- if (TREE_CODE (f) == FUNCTION_DECL && DECL_CONTEXT (f) != NULL_TREE)
- {
- tree context = DECL_CONTEXT (f);
- int index, interface = 0;
- RESERVE (5);
-
- /* If the method is not static, use the qualifying type.
- However, don't use the qualifying type if the method
- was declared in Object. */
- if (! METHOD_STATIC (f)
- && ! DECL_CONSTRUCTOR_P (f)
- && ! METHOD_PRIVATE (f)
- && DECL_CONTEXT (f) != object_type_node)
- {
- tree arg1 = TREE_VALUE (TREE_OPERAND (exp, 1));
- context = TREE_TYPE (TREE_TYPE (arg1));
- }
-
- if (METHOD_STATIC (f))
- OP1 (OPCODE_invokestatic);
- else if (DECL_CONSTRUCTOR_P (f) || CALL_USING_SUPER (exp)
- || METHOD_PRIVATE (f))
- OP1 (OPCODE_invokespecial);
- else
- {
- if (CLASS_INTERFACE (TYPE_NAME (context)))
- interface = 1;
- if (interface)
- OP1 (OPCODE_invokeinterface);
- else
- OP1 (OPCODE_invokevirtual);
- }
-
- index = find_methodref_with_class_index (&state->cpool, f,
- context);
- OP2 (index);
- if (interface)
- {
- gcc_assert (nargs > 0);
- OP1 (nargs);
- OP1 (0);
- }
- f = TREE_TYPE (TREE_TYPE (f));
- if (TREE_CODE (f) != VOID_TYPE)
- {
- int size = TYPE_IS_WIDE (f) ? 2 : 1;
- if (target == IGNORE_TARGET)
- emit_pop (size, state);
- else
- NOTE_PUSH (size);
- }
- break;
- }
- }
- /* fall through */
- default:
- error("internal error in generate_bytecode_insn - tree code not implemented: %s",
- tree_code_name [(int) TREE_CODE (exp)]);
- }
-}
-
-static void
-perform_relocations (struct jcf_partial *state)
-{
- struct jcf_block *block;
- struct jcf_relocation *reloc;
- int pc;
- int shrink;
-
- /* Before we start, the pc field of each block is an upper bound on
- the block's start pc (it may be less, if previous blocks need less
- than their maximum).
-
- The minimum size of each block is in the block's chunk->size. */
-
- /* First, 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->v.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->kind == OPCODE_goto_w
- && reloc->label->pc == block->next->pc
- && reloc->offset + 2 == block_size)
- {
- reloc = reloc->next;
- block->u.relocations = reloc;
- block->v.chunk->size -= 3;
- block_size -= 3;
- shrink += 3;
- }
-
- /* Optimize GOTO L; ... L: GOTO X by changing the first goto to
- jump directly to X. We're careful here to avoid an infinite
- loop if the `goto's themselves form one. We do this
- optimization because we can generate a goto-to-goto for some
- try/finally blocks. */
- while (reloc != NULL
- && reloc->kind == OPCODE_goto_w
- && reloc->label != block
- && reloc->label->v.chunk->data != NULL
- && reloc->label->v.chunk->data[0] == OPCODE_goto)
- {
- /* Find the reloc for the first instruction of the
- destination block. */
- struct jcf_relocation *first_reloc;
- for (first_reloc = reloc->label->u.relocations;
- first_reloc;
- first_reloc = first_reloc->next)
- {
- if (first_reloc->offset == 1
- && first_reloc->kind == OPCODE_goto_w)
- {
- reloc->label = first_reloc->label;
- break;
- }
- }
-
- /* If we didn't do anything, exit the loop. */
- if (first_reloc == NULL)
- break;
- }
-
- for (reloc = block->u.relocations; reloc != NULL; reloc = reloc->next)
- {
- if (reloc->kind == SWITCH_ALIGN_RELOC)
- {
- /* We assume this is the first relocation in this block,
- so we know its final pc. */
- int where = pc + reloc->offset;
- int pad = ((where + 3) & ~3) - where;
- block_size += pad;
- }
- else if (reloc->kind < -1 || reloc->kind > BLOCK_START_RELOC)
- {
- 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->v.chunk;
- int old_size = chunk->size;
- int next_pc = block->next == NULL ? pc : block->next->pc;
- int new_size = next_pc - block->pc;
- unsigned char *new_ptr;
- unsigned char *old_buffer = chunk->data;
- unsigned char *old_ptr = old_buffer + old_size;
- if (new_size != old_size)
- {
- chunk->data = obstack_alloc (state->chunk_obstack, new_size);
- chunk->size = new_size;
- }
- new_ptr = chunk->data + new_size;
-
- /* We do the relocations from back to front, because
- the relocations are in reverse order. */
- for (reloc = block->u.relocations; ; reloc = reloc->next)
- {
- /* new_ptr and old_ptr point into the old and new buffers,
- respectively. (If no relocations cause the buffer to
- grow, the buffer will be the same buffer, and new_ptr==old_ptr.)
- The bytes at higher address have been copied and relocations
- handled; those at lower addresses remain to process. */
-
- /* Lower old index of piece to be copied with no relocation.
- I.e. high index of the first piece that does need relocation. */
- int start = reloc == NULL ? 0
- : reloc->kind == SWITCH_ALIGN_RELOC ? reloc->offset
- : (reloc->kind == 0 || reloc->kind == BLOCK_START_RELOC)
- ? reloc->offset + 4
- : reloc->offset + 2;
- int32 value;
- int new_offset;
- int n = (old_ptr - old_buffer) - start;
- new_ptr -= n;
- old_ptr -= n;
- /* Don't "copy" bytes in place, this causes valgrind
- warnings. */
- if (n > 0 && new_ptr != old_ptr)
- memcpy (new_ptr, old_ptr, n);
- if (old_ptr == old_buffer)
- break;
-
- new_offset = new_ptr - chunk->data;
- new_offset -= (reloc->kind == -1 ? 2 : 4);
- if (reloc->kind == 0)
- {
- old_ptr -= 4;
- value = GET_u4 (old_ptr);
- }
- else if (reloc->kind == BLOCK_START_RELOC)
- {
- old_ptr -= 4;
- value = 0;
- new_offset = 0;
- }
- else if (reloc->kind == SWITCH_ALIGN_RELOC)
- {
- int where = block->pc + reloc->offset;
- int pad = ((where + 3) & ~3) - where;
- while (--pad >= 0)
- *--new_ptr = 0;
- continue;
- }
- else
- {
- old_ptr -= 2;
- value = GET_u2 (old_ptr);
- }
- 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 > BLOCK_START_RELOC)
- {
- /* 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;
- }
- }
- gcc_assert (new_ptr == chunk->data);
- }
- state->code_length = pc;
-}
-
-static void
-init_jcf_state (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);
-}
-
-static void
-init_jcf_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;
- state->handlers = NULL;
- state->last_handler = NULL;
- state->num_handlers = 0;
- state->num_finalizers = 0;
- state->return_value_decl = NULL_TREE;
-}
-
-static void
-release_jcf_state (struct jcf_partial *state)
-{
- CPOOL_FINISH (&state->cpool);
- obstack_free (state->chunk_obstack, state->first);
-}
-
-/* Get the access flags (modifiers) of a class (TYPE_DECL) to be used in the
- access_flags field of the class file header. */
-
-static int
-get_classfile_modifiers (tree class)
-{
- /* These are the flags which are valid class file modifiers.
- See JVMS2 S4.1. */
- int valid_toplevel_class_flags = (ACC_PUBLIC | ACC_FINAL | ACC_SUPER |
- ACC_INTERFACE | ACC_ABSTRACT);
- int flags = get_access_flags (class);
-
- /* ACC_SUPER should always be set, except for interfaces. */
- if (! (flags & ACC_INTERFACE))
- flags |= ACC_SUPER;
-
- /* A protected member class becomes public at the top level. */
- if (flags & ACC_PROTECTED)
- flags |= ACC_PUBLIC;
-
- /* Filter out flags that are not valid for a class or interface in the
- top-level access_flags field. */
- flags &= valid_toplevel_class_flags;
-
- return flags;
-}
-
-/* Get the access flags (modifiers) for a method to be used in the class
- file. */
-
-static int
-get_method_access_flags (tree decl)
-{
- int flags = get_access_flags (decl);
-
- /* Promote "private" inner-class constructors to package-private. */
- if (DECL_CONSTRUCTOR_P (decl)
- && INNER_CLASS_DECL_P (TYPE_NAME (DECL_CONTEXT (decl))))
- flags &= ~(ACC_PRIVATE);
-
- return flags;
-}
-
-/* Generate and return a list of chunks containing the class CLAS
- in the .class file representation. The list can be written to a
- .class file using write_chunks. Allocate chunks from obstack WORK. */
-
-static GTY(()) tree SourceFile_node;
-static struct chunk *
-generate_classfile (tree clas, struct jcf_partial *state)
-{
- struct chunk *cpool_chunk;
- const char *source_file, *s;
- unsigned char *ptr;
- int i;
- unsigned char *fields_count_ptr;
- int fields_count = 0;
- unsigned char *methods_count_ptr;
- int methods_count = 0;
- tree part;
- int total_supers
- = clas == object_type_node ? 0 : BINFO_N_BASE_BINFOS (TYPE_BINFO (clas));
-
- ptr = append_chunk (NULL, 8, state);
- PUT4 (0xCafeBabe); /* Magic number */
- PUT2 (3); /* Minor version */
- PUT2 (45); /* Major version */
-
- append_chunk (NULL, 0, state);
- cpool_chunk = state->chunk;
-
- /* Next allocate the chunk containing access_flags through fields_count. */
- if (clas == object_type_node)
- i = 10;
- else
- i = 8 + 2 * total_supers;
- ptr = append_chunk (NULL, i, state);
- i = get_classfile_modifiers (TYPE_NAME (clas));
- PUT2 (i); /* access_flags */
- i = find_class_constant (&state->cpool, clas); PUT2 (i); /* this_class */
- if (clas == object_type_node)
- {
- PUT2(0); /* super_class */
- PUT2(0); /* interfaces_count */
- }
- else
- {
- tree binfo = TYPE_BINFO (clas);
- tree base_binfo = BINFO_BASE_BINFO (binfo, 0);
- int j = find_class_constant (&state->cpool, BINFO_TYPE (base_binfo));
-
- PUT2 (j); /* super_class */
- PUT2 (total_supers - 1); /* interfaces_count */
- for (i = 1; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
- {
- j = find_class_constant (&state->cpool, BINFO_TYPE (base_binfo));
- PUT2 (j);
- }
- }
- fields_count_ptr = ptr;
-
- for (part = TYPE_FIELDS (clas); part; part = TREE_CHAIN (part))
- {
- int have_value, attr_count = 0;
- if (DECL_NAME (part) == NULL_TREE || DECL_ARTIFICIAL (part))
- continue;
- ptr = append_chunk (NULL, 8, state);
- i = get_access_flags (part); PUT2 (i);
- 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);
- have_value = DECL_INITIAL (part) != NULL_TREE
- && FIELD_STATIC (part) && CONSTANT_VALUE_P (DECL_INITIAL (part))
- && FIELD_FINAL (part)
- && (JPRIMITIVE_TYPE_P (TREE_TYPE (part))
- || TREE_TYPE (part) == string_ptr_type_node);
- if (have_value)
- attr_count++;
-
- 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)
- {
- tree init = DECL_INITIAL (part);
- static tree ConstantValue_node = NULL_TREE;
- if (TREE_TYPE (part) != TREE_TYPE (init))
- fatal_error ("field initializer type mismatch");
- ptr = append_chunk (NULL, 8, state);
- if (ConstantValue_node == NULL_TREE)
- ConstantValue_node = get_identifier ("ConstantValue");
- i = find_utf8_constant (&state->cpool, ConstantValue_node);
- PUT2 (i); /* attribute_name_index */
- PUT4 (2); /* attribute_length */
- i = find_constant_index (init, state); PUT2 (i);
- }
- /* Emit the "Synthetic" attribute for val$<x> and this$<n>
- fields and other fields which need it. */
- 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);
-
- 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 function_body = DECL_FUNCTION_BODY (part);
- tree body = function_body == NULL_TREE ? NULL_TREE
- : BLOCK_EXPR_BODY (function_body);
- tree name = DECL_CONSTRUCTOR_P (part) ? init_identifier_node
- : DECL_NAME (part);
- 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_method_access_flags (part); PUT2 (i);
- i = find_utf8_constant (&state->cpool, name); PUT2 (i);
- i = find_utf8_constant (&state->cpool, build_java_signature (type));
- PUT2 (i);
- i = (body != NULL_TREE) + (DECL_FUNCTION_THROWS (part) != NULL_TREE);
-
- /* Make room for the Synthetic attribute (of zero length.) */
- if (DECL_FINIT_P (part)
- || DECL_INSTINIT_P (part)
- || NESTED_FIELD_ACCESS_IDENTIFIER_P (DECL_NAME (part))
- || TYPE_DOT_CLASS (clas) == part)
- {
- i++;
- synthetic_p = 1;
- }
- /* Make room for Deprecated attribute. */
- if (METHOD_DEPRECATED (part))
- i++;
-
- PUT2 (i); /* attributes_count */
-
- if (synthetic_p)
- ptr = append_synthetic_attribute (state);
-
- if (body != NULL_TREE)
- {
- int code_attributes_count = 0;
- static tree Code_node = NULL_TREE;
- tree t;
- unsigned char *attr_len_ptr;
- struct jcf_handler *handler;
- if (Code_node == NULL_TREE)
- Code_node = get_identifier ("Code");
- ptr = append_chunk (NULL, 14, state);
- i = find_utf8_constant (&state->cpool, Code_node); PUT2 (i);
- attr_len_ptr = ptr;
- 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, state);
- state->num_jsrs = 0;
- generate_bytecode_insns (body, IGNORE_TARGET, state);
- if (CAN_COMPLETE_NORMALLY (body))
- {
- gcc_assert (TREE_CODE (TREE_TYPE (type)) == VOID_TYPE);
- RESERVE (1);
- OP1 (OPCODE_return);
- }
- for (t = DECL_ARGUMENTS (part); t != NULL_TREE; t = TREE_CHAIN (t))
- maybe_free_localvar (t, state, 1);
- if (state->return_value_decl != NULL_TREE)
- maybe_free_localvar (state->return_value_decl, state, 1);
- finish_jcf_block (state);
- perform_relocations (state);
-
- ptr = attr_len_ptr;
- i = 8 + state->code_length + 4 + 8 * state->num_handlers;
- if (state->linenumber_count > 0)
- {
- code_attributes_count++;
- i += 8 + 4 * state->linenumber_count;
- }
- if (state->lvar_count > 0)
- {
- code_attributes_count++;
- i += 8 + 10 * state->lvar_count;
- }
- UNSAFE_PUT4 (i); /* attribute_length */
- UNSAFE_PUT2 (state->code_SP_max); /* max_stack */
- UNSAFE_PUT2 (localvar_max); /* max_locals */
- UNSAFE_PUT4 (state->code_length);
-
- /* Emit the exception table. */
- ptr = append_chunk (NULL, 2 + 8 * state->num_handlers, state);
- PUT2 (state->num_handlers); /* exception_table_length */
- handler = state->handlers;
- for (; handler != NULL; handler = handler->next)
- {
- int type_index;
- PUT2 (handler->start_label->pc);
- PUT2 (handler->end_label->pc);
- PUT2 (handler->handler_label->pc);
- if (handler->type == NULL_TREE)
- type_index = 0;
- else
- type_index = find_class_constant (&state->cpool,
- handler->type);
- PUT2 (type_index);
- }
-
- ptr = append_chunk (NULL, 2, state);
- PUT2 (code_attributes_count);
-
- /* Write the LineNumberTable attribute. */
- if (state->linenumber_count > 0)
- {
- static tree LineNumberTable_node = NULL_TREE;
- ptr = append_chunk (NULL,
- 8 + 4 * state->linenumber_count, state);
- if (LineNumberTable_node == NULL_TREE)
- LineNumberTable_node = get_identifier ("LineNumberTable");
- i = find_utf8_constant (&state->cpool, LineNumberTable_node);
- PUT2 (i); /* attribute_name_index */
- 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 (state->lvar_count > 0)
- {
- static tree LocalVariableTable_node = NULL_TREE;
- 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 (&state->cpool, LocalVariableTable_node);
- PUT2 (i); /* attribute_name_index */
- 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);
- }
- }
- }
- if (DECL_FUNCTION_THROWS (part) != NULL_TREE)
- {
- tree t = DECL_FUNCTION_THROWS (part);
- int throws_count = list_length (t);
- static tree Exceptions_node = NULL_TREE;
- if (Exceptions_node == NULL_TREE)
- Exceptions_node = get_identifier ("Exceptions");
- ptr = append_chunk (NULL, 8 + 2 * throws_count, state);
- i = find_utf8_constant (&state->cpool, Exceptions_node);
- PUT2 (i); /* attribute_name_index */
- i = 2 + 2 * throws_count; PUT4(i); /* attribute_length */
- i = throws_count; PUT2 (i);
- for (; t != NULL_TREE; t = TREE_CHAIN (t))
- {
- i = find_class_constant (&state->cpool, TREE_VALUE (t));
- PUT2 (i);
- }
- }
-
- if (METHOD_DEPRECATED (part))
- append_deprecated_attribute (state);
-
- methods_count++;
- current_function_decl = save_function;
- }
- ptr = methods_count_ptr; UNSAFE_PUT2 (methods_count);
-
- source_file = DECL_SOURCE_FILE (TYPE_NAME (clas));
- for (s = source_file; ; s++)
- {
- char ch = *s;
- if (ch == '\0')
- break;
- if (ch == '/' || ch == '\\')
- source_file = s+1;
- }
- ptr = append_chunk (NULL, 10, state);
-
- i = 1; /* Source file always exists as an attribute */
- if (INNER_CLASS_TYPE_P (clas) || DECL_INNER_CLASS_LIST (TYPE_NAME (clas)))
- i++;
- if (clas == object_type_node)
- i++;
- if (CLASS_DEPRECATED (TYPE_NAME (clas)))
- i++;
-
- PUT2 (i); /* 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);
- 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);
- ptr = obstack_alloc (state->chunk_obstack, i);
- cpool_chunk->data = ptr;
- cpool_chunk->size = i;
- write_constant_pool (&state->cpool, ptr, i);
- return state->first;
-}
-
-static GTY(()) tree Synthetic_node;
-static unsigned char *
-append_synthetic_attribute (struct jcf_partial *state)
-{
- unsigned char *ptr = append_chunk (NULL, 6, state);
- int i;
-
- if (Synthetic_node == NULL_TREE)
- {
- Synthetic_node = get_identifier ("Synthetic");
- }
- i = find_utf8_constant (&state->cpool, Synthetic_node);
- PUT2 (i); /* Attribute string index */
- PUT4 (0); /* Attribute length */
-
- return ptr;
-}
-
-static void
-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;
-
- if (class != object_type_node)
- return;
-
- ptr = append_chunk (NULL, 6, state); /* 2+4 */
- i = find_utf8_constant (&state->cpool,
- get_identifier ("gnu.gcj.gcj-compiled"));
- PUT2 (i); /* Attribute string index */
- PUT4 (0); /* Attribute length */
-}
-
-static tree InnerClasses_node;
-static void
-append_innerclasses_attribute (struct jcf_partial *state, tree class)
-{
- tree orig_decl = TYPE_NAME (class);
- tree current, decl;
- int length = 0, i;
- unsigned char *ptr, *length_marker, *number_marker;
-
- if (!INNER_CLASS_TYPE_P (class) && !DECL_INNER_CLASS_LIST (orig_decl))
- return;
-
- ptr = append_chunk (NULL, 8, state); /* 2+4+2 */
-
- if (InnerClasses_node == NULL_TREE)
- {
- InnerClasses_node = get_identifier ("InnerClasses");
- }
- i = find_utf8_constant (&state->cpool, InnerClasses_node);
- PUT2 (i);
- length_marker = ptr; PUT4 (0); /* length, to be later patched */
- number_marker = ptr; PUT2 (0); /* number of classes, tblp */
-
- /* Generate the entries: all inner classes visible from the one we
- process: itself, up and down. */
- while (class && INNER_CLASS_TYPE_P (class))
- {
- const char *n;
-
- decl = TYPE_NAME (class);
- n = IDENTIFIER_POINTER (DECL_NAME (decl)) +
- IDENTIFIER_LENGTH (DECL_NAME (decl));
-
- while (n[-1] != '$')
- n--;
- append_innerclasses_attribute_entry (state, decl, get_identifier (n));
- length++;
-
- class = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (class)));
- }
-
- decl = orig_decl;
- for (current = DECL_INNER_CLASS_LIST (decl);
- current; current = TREE_CHAIN (current))
- {
- append_innerclasses_attribute_entry (state, TREE_PURPOSE (current),
- TREE_VALUE (current));
- length++;
- }
-
- ptr = length_marker; PUT4 (8*length+2);
- ptr = number_marker; PUT2 (length);
-}
-
-static void
-append_innerclasses_attribute_entry (struct jcf_partial *state,
- tree decl, tree name)
-{
- int icii, icaf;
- int ocii = 0, ini = 0;
- unsigned char *ptr = append_chunk (NULL, 8, state);
-
- icii = find_class_constant (&state->cpool, TREE_TYPE (decl));
-
- /* Sun's implementation seems to generate ocii to 0 for inner
- classes (which aren't considered members of the class they're
- in.) The specs are saying that if the class is anonymous,
- inner_name_index must be zero. */
- if (!ANONYMOUS_CLASS_P (TREE_TYPE (decl)))
- {
- ocii = find_class_constant (&state->cpool,
- TREE_TYPE (DECL_CONTEXT (decl)));
- ini = find_utf8_constant (&state->cpool, name);
- }
- icaf = get_access_flags (decl);
-
- PUT2 (icii); PUT2 (ocii); PUT2 (ini); PUT2 (icaf);
-}
-
-static char *
-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,
- ".class"));
- if (jcf_write_base_directory == NULL)
- {
- /* Make sure we put the class file into the .java file's
- directory, and not into some subdirectory thereof. */
- char *t;
- dname = DECL_SOURCE_FILE (TYPE_NAME (clas));
- slash = strrchr (dname, DIR_SEPARATOR);
-#ifdef DIR_SEPARATOR_2
- if (! slash)
- 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 = XNEWVEC (char, slash - dname + strlen (cname) + 2);
- strncpy (r, dname, slash - dname);
- r[slash - dname] = sep;
- strcpy (&r[slash - dname + 1], cname);
-
- /* We try to make new directories when we need them. We only do
- this for directories which "might not" exist. For instance, we
- assume the `-d' directory exists, but we don't assume that any
- subdirectory below it exists. It might be worthwhile to keep
- track of which directories we've created to avoid gratuitous
- stat()s. */
- dname = r + (slash - dname) + 1;
- while (1)
- {
- char *s = strchr (dname, sep);
- if (s == NULL)
- break;
- *s = '\0';
- /* Try to make directory if it doesn't already exist. */
- if (stat (r, &sb) == -1
- && mkdir (r, 0755) == -1
- /* The directory might have been made by another process. */
- && errno != EEXIST)
- fatal_error ("can't create directory %s: %m", r);
-
- *s = sep;
- /* Skip consecutive separators. */
- for (dname = s + 1; *dname && *dname == sep; ++dname)
- ;
- }
-
- return r;
-}
-
-/* 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 (tree clas)
-{
- struct obstack *work = &temporary_obstack;
- struct jcf_partial state[1];
- char *class_file_name = make_class_file_name (clas);
- struct chunk *chunks;
-
- if (class_file_name != NULL)
- {
- FILE *stream;
- char *temporary_file_name;
- char pid [sizeof (long) * 2 + 2];
-
- /* The .class file is initially written to a ".PID" file so that
- if multiple instances of the compiler are running at once
- they do not see partially formed class files nor override
- each other, which may happen in libjava with parallel build.
- */
- sprintf (pid, ".%lx", (unsigned long) getpid ());
- temporary_file_name = concat (class_file_name, pid, NULL);
- stream = fopen (temporary_file_name, "wb");
- if (stream == NULL)
- 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_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 behavior
- is implementation-defined. ISO 9899-1990 7.9.4.2.
-
- For example, on Win32 with MSVCRT, it is an error. */
-
- unlink (class_file_name);
-
- if (rename (temporary_file_name, class_file_name) == -1)
- {
- int errno_saved = errno;
- remove (temporary_file_name);
- errno = errno_saved;
- fatal_error ("can't create %s: %m", class_file_name);
- }
- free (temporary_file_name);
- free (class_file_name);
- }
- release_jcf_state (state);
-}
-
-/* TODO:
- string concatenation
- synchronized statement
- */
-
-#include "gt-java-jcf-write.h"
Index: lang.c
===================================================================
--- lang.c (revision 117511)
+++ lang.c (working copy)
@@ -337,7 +337,7 @@
break;
case OPT_foutput_class_dir_:
- jcf_write_base_directory = arg;
+ /* FIXME: remove; this is handled by ecj1 now. */
break;
case OPT_version: