Initial revision

From-SVN: r22299
This commit is contained in:
Anthony Green 1998-09-06 15:36:06 +00:00
parent fc08e32958
commit e04a16fbee
43 changed files with 39504 additions and 0 deletions

209
gcc/java/Make-lang.in Normal file
View file

@ -0,0 +1,209 @@
# Top level makefile fragment for the GNU compiler for the Java(TM)
# language.
# Copyright (C) 1996, 1998 Free Software Foundation, Inc.
#This file is part of GNU CC.
#GNU CC 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.
#GNU CC 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 GNU CC; see the file COPYING. If not, write to
#the Free Software Foundation, 59 Temple Place - Suite 330,
#Boston, MA 02111-1307, 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.
# This file provides the language dependent support in the main Makefile.
# Each language makefile fragment must provide the following targets:
#
# foo.all.build, foo.all.cross, foo.start.encap, foo.rest.encap,
# foo.info, foo.dvi,
# foo.install-normal, foo.install-common, foo.install-info, foo.install-man,
# foo.uninstall, foo.distdir,
# foo.mostlyclean, foo.clean, foo.distclean, foo.extraclean,
# foo.maintainer-clean, foo.stage1, foo.stage2, foo.stage3, foo.stage4
#
# where `foo' is the name of the language.
#
# It should also provide rules for:
#
# - making any compiler driver (eg: g++)
# - the compiler proper (eg: jc1)
# - define the names for selecting the language in LANGUAGES.
# Extra flags to pass to recursive makes.
JAVA_FLAGS_TO_PASS = \
"JAVA_FOR_BUILD=$(JAVA_FOR_BUILD)" \
"JAVAFLAGS=$(JAVAFLAGS)" \
"JAVA_FOR_TARGET=$(JAVA_FOR_TARGET)"
# Actual names to use when installing a native compiler.
JAVA_INSTALL_NAME = `t='$(program_transform_name)'; echo gcj | sed $$t`
# Actual names to use when installing a cross-compiler.
JAVA_CROSS_NAME = `t='$(program_transform_cross_name)'; echo gcj | sed $$t`
# Define the names for selecting java in LANGUAGES.
java: jc1$(exeext) $(GCJ)$(exeext) jvgenmain$(exeext) gcjh$(exeext)
# Define the name of target independant tools to be installed in $(bindir)
# Names are subject to changes
JAVA_TARGET_INDEPENDENT_BIN_TOOLS = gcjh jv-scan jcf-dump
# Tell GNU make to ignore these if they exist.
.PHONY: java
GCJ = gcj
# Remember to keep this list in sync with JAVA_OBJS in Makefile.in!!!
#
JAVA_SRCS = $(srcdir)/java/parse.y $(srcdir)/java/class.c \
$(srcdir)/java/decl.c $(srcdir)/java/expr.c $(srcdir)/java/constants.c \
$(srcdir)/java/lang.c $(srcdir)/java/typeck.c $(srcdir)/java/except.c \
$(srcdir)/java/verify.c $(srcdir)/java/zextract.c $(srcdir)/java/jcf-io.c \
$(srcdir)/java/jcf-parse.c $(srcdir)/java/mangle.c \
$(srcdir)/java/jcf-write.c $(srcdir)/java/buffer.c
jc1$(exeext): $(P) $(JAVA_SRCS) $(LIBDEPS) stamp-objlist
cd java; $(MAKE) $(FLAGS_TO_PASS) $(JAVA_FLAGS_TO_PASS) ../jc1$(exeext)
$(GCJ).c: $(srcdir)/gcc.c
-rm -f $@
$(LN_S) $(srcdir)/gcc.c $@
jvspec.o: $(srcdir)/java/jvspec.c
$(CC) -c -DWITH_THREAD_$(GCC_THREAD_FILE) \
$(ALL_CFLAGS) $(ALL_CPPFLAGS) \
$(INCLUDES) $(srcdir)/java/jvspec.c
# N.B.: This is a copy of the gcc.o rule, with -DLANG_SPECIFIC_DRIVER added.
# It'd be nice if we could find an easier way to do this---rather than have
# to track changes to the toplevel gcc Makefile as well.
# We depend on $(GCJ).c last, to make it obvious where it came from.
$(GCJ).o: $(CONFIG_H) multilib.h config.status $(lang_specs_files) $(GCJ).c \
system.h
$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
$(DRIVER_DEFINES) \
-DLANG_SPECIFIC_DRIVER \
-c $(GCJ).c
# Create the compiler driver for $(GCJ).
$(GCJ)$(exeext): $(GCJ).o jvspec.o version.o choose-temp.o\
pexecute.o prefix.o mkstemp.o $(LIBDEPS) $(EXTRA_GCC_OBJS)
$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ $(GCJ).o jvspec.o prefix.o \
version.o choose-temp.o pexecute.o mkstemp.o $(EXTRA_GCC_OBJS) $(LIBS)
# Create a version of the $(GCJ) driver which calls the cross-compiler.
$(GCJ)-cross$(exeext): $(GCJ)$(exeext)
-rm -f $(GCJ)-cross$(exeext)
cp $(GCJ)$(exeext) $(GCJ)-cross$(exeext)
# Dependencies here must be kept in sync with dependencies in Makefile.in.
jvgenmain$(exeext): $(srcdir)/java/jvgenmain.c $(srcdir)/java/mangle.c \
$(OBSTACK)
cd java && $(MAKE) $(FLAGS_TO_PASS) $(JAVA_FLAGS_TO_PASS) ../jvgenmain$(exeext)
# This must be kept in sync with dependencies in Makefile.in.
GCJH_SOURCES = $(srcdir)/java/gjavah.c $(srcdir)/java/jcf-io.c \
$(srcdir)/java/zextract.c $(srcdir)/java/jcf-reader.c \
$(srcdir)/java/jcf.h $(srcdir)/java/javaop.h \
$(srcdir)/java/javaop.def
gcjh$(exeext): $(GCJH_SOURCES)
cd java && $(MAKE) $(FLAGS_TO_PASS) $(JAVA_FLAGS_TO_PASS) ../gcjh$(exeext)
# Build hooks:
java.all.build: $(GCJ)$(exeext) jvgenmain$(exeext) gcjh$(exeext)
java.all.cross: $(GCJ)-cross$(exeext) jvgenmain$(exeext) gcjh$(exeext)
java.start.encap: $(GCJ)$(exeext)
java.rest.encap: jvgenmain$(exeext) gcjh$(exeext)
java.info:
# Install hooks:
# jc1, gcj, jvgenmain, and gcjh are installed elsewhere as part
# of $(COMPILERS).
# Nothing to do here.
java.install-normal:
java.install-common:
-if [ -f $(GCJ)$(exeext) ]; then \
if [ -f $(GCJ)-cross$(exeext) ]; then \
rm -f $(bindir)/$(JAVA_CROSS_NAME)$(exeext); \
$(INSTALL_PROGRAM) $(GCJ)-cross$(exeext) $(bindir)/$(JAVA_CROSS_NAME)$(exeext); \
chmod a+x $(bindir)/$(JAVA_CROSS_NAME)$(exeext); \
else \
rm -f $(bindir)/$(JAVA_INSTALL_NAME)$(exeext); \
$(INSTALL_PROGRAM) $(GCJ)$(exeext) $(bindir)/$(JAVA_INSTALL_NAME)$(exeext); \
chmod a+x $(bindir)/$(JAVA_INSTALL_NAME)$(exeext); \
fi ; \
fi ; \
for tool in $(JAVA_TARGET_INDEPENDENT_BIN_TOOLS); do \
if [ -f $$tool$(exeext) ]; then \
rm -f $(bindir)/$$tool$(exeext); \
$(INSTALL_PROGRAM) $$tool$(exeext) $(bindir)/$$tool$(exeext); \
chmod a+x $(bindir)/$$tool$(exeext); \
fi ; \
done
java.install-man:
java.uninstall:
-rm -rf $(bindir)/$(JAVA_INSTALL_NAME)$(exeext)
-rm -rf $(bindir)/$(JAVA_CROSS_NAME)$(exeext)
java.install-info:
# Clean hooks:
# A lot of the ancillary files are deleted by the main makefile.
# We just have to delete files specific to us.
java.mostlyclean:
-rm -f java/*$(objext) $(DEMANGLER_PROG)
java.clean:
java.distclean:
-rm -f java/config.status java/Makefile
-rm -f java/parse.output
java.extraclean:
java.maintainer-clean:
-rm -f java/parse.h
# Stage hooks:
# The main makefile has already created stage?/java.
java.stage1:
-mv java/*$(objext) stage1/java
java.stage2:
-mv java/*$(objext) stage2/java
java.stage3:
-mv java/*$(objext) stage3/java
java.stage4:
-mv java/*$(objext) stage4/java
# Maintenance hooks:
# This target creates the files that can be rebuilt, but go in the
# distribution anyway. It then copies the files to the distdir directory.
java.distdir:
mkdir tmp/java
cd java ; $(MAKE) $(FLAGS_TO_PASS) $(JAVA_FLAGS_TO_PASS) parse.c hash.h
cd java; \
for file in *[0-9a-zA-Z+]; do \
ln $$file ../tmp/java >/dev/null 2>&1 || cp $$file ../tmp/java; \
done

258
gcc/java/Makefile.in Normal file
View file

@ -0,0 +1,258 @@
# Makefile for GNU compiler for the Java(TM) language.
# Copyright (C) 1987, 88, 90-4, 1995, 1998 Free Software Foundation, Inc.
#This file is part of GNU CC.
#GNU CC 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.
#GNU CC 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 GNU CC; see the file COPYING. If not, write to
#the Free Software Foundation, 59 Temple Place - Suite 330,
#Boston, MA 02111-1307, 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.
# The makefile built from this file lives in the language subdirectory.
# Its purpose is to provide support for:
#
# 1) recursion where necessary, and only then (building .o's), and
# 2) building and debugging cc1 from the language subdirectory, and
# 3) nothing else.
#
# The parent makefile handles all other chores, with help from the
# language makefile fragment, of course.
#
# The targets for external use are:
# all, TAGS, ???mostlyclean, ???clean.
# Suppress smart makes who think they know how to automake Yacc files
.y.c:
# Variables that exist for you to override.
# See below for how to change them for certain systems.
ALLOCA =
# Various ways of specifying flags for compilations:
# CFLAGS is for the user to override to, e.g., do a bootstrap with -O2.
# BOOT_CFLAGS is the value of CFLAGS to pass
# to the stage2 and stage3 compilations
# XCFLAGS is used for most compilations but not when using the GCC just built.
XCFLAGS =
CFLAGS = -g
BOOT_CFLAGS = -O $(CFLAGS)
# These exists to be overridden by the x-* and t-* files, respectively.
X_CFLAGS =
T_CFLAGS =
X_CPPFLAGS =
T_CPPFLAGS =
CC = @CC@
BISON = `if [ -f ../../bison/bison ] ; then echo ../../bison/bison -L $(srcdir)/../../bison/ ; else echo bison ; fi`
BISONFLAGS =
JAVABISONFLAGS = --name-prefix=java_
LEX = `if [ -f ../../flex/flex ] ; then echo ../../flex/flex ; else echo flex ; fi`
LEXFLAGS =
AR = ar
AR_FLAGS = rc
SHELL = /bin/sh
MAKEINFO = makeinfo
TEXI2DVI = texi2dvi
# Define this as & to perform parallel make on a Sequent.
# Note that this has some bugs, and it seems currently necessary
# to compile all the gen* files first by hand to avoid erroneous results.
P =
# This is used in the definition of SUBDIR_USE_ALLOCA.
# ??? Perhaps it would be better if it just looked for *gcc*.
OLDCC = cc
# This is used instead of ALL_CFLAGS when compiling with GCC_FOR_TARGET.
# It omits XCFLAGS, and specifies -B./.
# It also specifies -B$(tooldir)/ to find as and ld for a cross compiler.
GCC_CFLAGS=$(INTERNAL_CFLAGS) $(X_CFLAGS) $(T_CFLAGS) $(CFLAGS)
# Tools to use when building a cross-compiler.
# These are used because `configure' appends `cross-make'
# to the makefile when making a cross-compiler.
# We don't use cross-make. Instead we use the tools
# from the build tree, if they are available.
# program_transform_name and objdir are set by configure.in.
program_transform_name =
objdir = .
+target=@target@
+xmake_file=@dep_host_xmake_file@
+tmake_file=@dep_tmake_file@
#version=`sed -e 's/.*\"\([^ \"]*\)[ \"].*/\1/' < $(srcdir)/version.c`
#mainversion=`sed -e 's/.*\"\([0-9]*\.[0-9]*\).*/\1/' < $(srcdir)/version.c`
# Directory where sources are, from where we are.
srcdir = @srcdir@
VPATH = @srcdir@
# Additional system libraries to link with.
CLIB=
# Change this to a null string if obstacks are installed in the
# system library.
OBSTACK=obstack.o
# Choose the real default target.
ALL=all
# End of variables for you to override.
# Definition of `all' is here so that new rules inserted by sed
# do not specify the default target.
all: all.indirect
# This tells GNU Make version 3 not to put all variables in the environment.
.NOEXPORT:
# sed inserts variable overrides after the following line.
####target overrides
@target_overrides@
####host overrides
@host_overrides@
####cross overrides
@cross_overrides@
####build overrides
@build_overrides@
####site overrides
# Now figure out from those variables how to compile and link.
all.indirect: Makefile ../jc1$(exeext) ../jcf-dump$(exeext) \
../jvgenmain$(exeext) ../gcjh$(exeext) ../jv-scan$(exeext)
# IN_GCC tells obstack.h that we are using gcc's <stddef.h> file.
INTERNAL_CFLAGS = $(CROSS) -DIN_GCC @extra_c_flags@
# This is the variable actually used when we compile.
ALL_CFLAGS = $(INTERNAL_CFLAGS) $(X_CFLAGS) $(T_CFLAGS) $(CFLAGS) $(XCFLAGS)
# Likewise.
ALL_CPPFLAGS = $(CPPFLAGS) $(X_CPPFLAGS) $(T_CPPFLAGS)
# Even if ALLOCA is set, don't use it if compiling with GCC.
SUBDIR_OBSTACK = `if [ x$(OBSTACK) != x ]; then echo ../$(OBSTACK); else true; fi`
SUBDIR_USE_ALLOCA = `case "${CC}" in "${OLDCC}") if [ x$(ALLOCA) != x ]; then echo ../$(ALLOCA); else true; fi ;; esac`
SUBDIR_MALLOC = `if [ x$(MALLOC) != x ]; then echo ../$(MALLOC); else true; fi`
# How to link with both our special library facilities
# and the system's installed libraries.
LIBS = $(SUBDIR_OBSTACK) $(SUBDIR_USE_ALLOCA) $(SUBDIR_MALLOC) $(CLIB)
# Specify the directories to be searched for header files.
# Both . and srcdir are used, in that order,
# so that tm.h and config.h will be found in the compilation
# subdirectory rather than in the source directory.
INCLUDES = -I. -I.. -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../config
# Always use -I$(srcdir)/config when compiling.
.c.o:
$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $<
# This tells GNU make version 3 not to export all the variables
# defined in this file into the environment.
.NOEXPORT:
# Lists of files for various purposes.
# Language-specific object files for Gcc/Java:
# Remember to keep this list in sync with JAVA_SRCS in Make-lang.in!!!
#
JAVA_OBJS = parse.o class.o decl.o expr.o constants.o lang.o typeck.o \
except.o verify.o zextract.o jcf-io.o jcf-parse.o mangle.o jcf-write.o \
buffer.o
JAVA_OBJS_LITE = parse-scan.o jv-scan.o
# Language-independent object files.
OBJS = `cat ../stamp-objlist`
OBJDEPS = ../stamp-objlist
compiler: ../jc1$(exeext) ../jv-scan$(exeext)
../jc1$(exeext): $(P) $(JAVA_OBJS) $(OBJDEPS) $(LIBDEPS)
rm -f ../jc1$(exeext)
$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ \
$(JAVA_OBJS) $(OBJS) $(LIBS)
../jv-scan$(exeext): $(P) $(JAVA_OBJS_LITE) $(OBJDEPS) $(LIBDEPS)
rm -f ../jv-scan$(exeext)
$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ \
$(JAVA_OBJS_LITE) $(LIBS)
../jcf-dump$(exeext): jcf-dump.o jcf-io.o zextract.o
$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ jcf-dump.o jcf-io.o zextract.o
# Dependencies here must be kept in sync with dependencies in Make-lang.in.
../jvgenmain$(exeext): jvgenmain.o mangle.o
$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ jvgenmain.o mangle.o ../obstack.o
../gcjh$(exeext): gjavah.o jcf-io.o zextract.o
$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ gjavah.o jcf-io.o zextract.o
Makefile: $(srcdir)/Makefile.in $(srcdir)/../configure
cd ..; $(SHELL) config.status
native: config.status ../jc1$(exeext)
# Compiling object files from source files.
PARSE_H = $(srcdir)/parse.h
PARSE_C = $(srcdir)/parse.c
PARSE_SCAN_C = $(srcdir)/parse-scan.c
$(PARSE_H): $(PARSE_C)
$(PARSE_C): $(srcdir)/parse.y $(srcdir)/lex.c $(PARSE_H) $(srcdir)/lex.h
$(BISON) -t -v $(BISONFLAGS) $(JAVABISONFLAGS) -o $(PARSE_C) \
$(srcdir)/parse.y
$(PARSE_SCAN_C): $(srcdir)/parse-scan.y $(srcdir)/lex.c $(PARSE_H) \
$(srcdir)/lex.h
$(BISON) -t -v $(BISONFLAGS) -o $(PARSE_SCAN_C) $(srcdir)/parse-scan.y
lex.c: keyword.h lex.h
keyword.h: keyword.gperf
gperf -p -t -j1 -i 1 -g -o -N java_keyword -k1,3,$$ \
keyword.gperf > keyword.h
# These exist for maintenance purposes.
# Update the tags table.
TAGS: force
cd $(srcdir) ; \
etags *.c *.h ; \
echo 'l' | tr 'l' '\f' >> TAGS ; \
echo 'parse.y,0' >> TAGS ; \
etags -a ../*.h ../*.c;
.PHONY: TAGS
mostlyclean:
rm -f *.o
clean: mostlyclean
rm -f parse.c
force:
parse.o: $(PARSE_C) jcf-reader.c
jcf-dump.o: jcf-reader.c jcf.h javaop.h javaop.def
gjavah.o: jcf-reader.c jcf.h javaop.h

50
gcc/java/buffer.c Normal file
View file

@ -0,0 +1,50 @@
/* A "buffer" utility type.
Copyright (C) 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC 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.
GNU CC 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* Written by Per Bothner <bothner@cygnus.com>, July 1998. */
#include "gansidecl.h"
#include "buffer.h"
/* Grow BUFP so there is room for at least SIZE more bytes. */
void
buffer_grow (bufp, size)
struct buffer *bufp;
int size;
{
if (bufp->limit - bufp->ptr >= size)
return;
if (bufp->data == 0)
{
if (size < 120)
size = 120;
bufp->data = (unsigned char*) xmalloc (size);
bufp->ptr = bufp->data;
}
else
{
int index = bufp->ptr - bufp->data;
size += 2 * (bufp->limit - bufp->data);
bufp->data = (unsigned char *) xrealloc (bufp->data, size);
bufp->ptr = bufp->data + index;
}
bufp->limit = bufp->data + size;
}

43
gcc/java/buffer.h Normal file
View file

@ -0,0 +1,43 @@
/* A "buffer" utility type.
Copyright (C) 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC 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.
GNU CC 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* Written by Per Bothner <bothner@cygnus.com>, July 1998. */
/* A simple data structure for an expandable buffer. */
struct buffer
{
/* The start of the actual data buffer. */
unsigned char *data;
/* Where to write next in the buffer. */
unsigned char *ptr;
/* The end of the allocated data buffer. */
unsigned char *limit;
};
#define NULL_BUFFER { (void*) 0, (void*) 0, (void*) 0 }
#define BUFFER_LENGTH(BUFP) ((BUFP)->ptr - (BUFP)->data)
#define BUFFER_RESET(BUFP) ((BUFP)->ptr = (BUFP)->data)
extern void buffer_grow PROTO ((struct buffer*, int));

1601
gcc/java/class.c Normal file

File diff suppressed because it is too large Load diff

40
gcc/java/config-lang.in Normal file
View file

@ -0,0 +1,40 @@
# Top level configure fragment for the GNU compiler for the Java(TM)
# language.
# Copyright (C) 1994, 1995 Free Software Foundation, Inc.
#This file is part of GNU CC.
#GNU CC 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.
#GNU CC 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 GNU CC; see the file COPYING. If not, write to
#the Free Software Foundation, 59 Temple Place - Suite 330,
#Boston, MA 02111-1307, 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.
# Configure looks for the existence of this file to auto-config each language.
# We define several parameters used by configure:
#
# language - name of language as it would appear in $(LANGUAGES)
# compilers - value to add to $(COMPILERS)
# stagestuff - files to add to $(STAGESTUFF)
# diff_excludes - files to ignore when building diffs between two versions.
language="java"
compilers="jc1\$(exeext) jvgenmain\$(exeext)"
stagestuff="jc1\$(exeext) gcj\$(exeext) jvgenmain\$(exeext) gcjh\$(exeext)"
outputs=java/Makefile

453
gcc/java/constants.c Normal file
View file

@ -0,0 +1,453 @@
/* Handle the constant pool of the Java(TM) Virtual Machine.
Copyright (C) 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC 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.
GNU CC 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, 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 "tree.h"
#include "java-tree.h"
#include "jcf.h"
#include "system.h"
extern struct obstack permanent_obstack;
/* Set the INDEX'th constant in CPOOL to have the given TAG and VALUE. */
void
set_constant_entry (cpool, index, tag, value)
CPool *cpool;
int index;
int tag;
jword value;
{
if (cpool->data == NULL)
{
cpool->capacity = 100;
cpool->tags = (uint8*) xmalloc (sizeof(uint8) * cpool->capacity);
cpool->data = (jword*) xmalloc (sizeof(jword) * cpool->capacity);
cpool->count = 1;
}
if (index >= cpool->capacity)
{
cpool->capacity *= 2;
if (index >= cpool->capacity)
cpool->capacity = index + 10;
cpool->tags = (uint8*) xrealloc (cpool->tags,
sizeof(uint8) * cpool->capacity);
cpool->data = (jword*) xrealloc (cpool->data,
sizeof(jword) * cpool->capacity);
}
if (index >= cpool->count)
cpool->count = index + 1;
cpool->tags[index] = tag;
cpool->data[index] = value;
}
/* Find (or create) a constant pool entry matching TAG and VALUE. */
int
find_constant1 (cpool, tag, value)
CPool *cpool;
int tag;
jword value;
{
int i;
for (i = cpool->count; --i > 0; )
{
if (cpool->tags[i] == tag && cpool->data[i] == value)
return i;
}
i = cpool->count == 0 ? 1 : cpool->count;
set_constant_entry (cpool, i, tag, value);
return i;
}
/* Find a double-word constant pool entry matching TAG and WORD1/WORD2. */
int
find_constant2 (cpool, tag, word1, word2)
CPool *cpool;
int tag;
jword word1, word2;
{
int i;
for (i = cpool->count - 1; --i > 0; )
{
if (cpool->tags[i] == tag
&& cpool->data[i] == word1
&& cpool->data[i+1] == word2)
return i;
}
i = cpool->count == 0 ? 1 : cpool->count;
set_constant_entry (cpool, i, tag, word1);
set_constant_entry (cpool, i+1, 0, word2);
return i;
}
int
find_utf8_constant (cpool, name)
CPool *cpool;
tree name;
{
if (name == NULL_TREE)
return 0;
return find_constant1 (cpool, CONSTANT_Utf8, (jword) name);
}
int
find_class_or_string_constant (cpool, tag, name)
CPool *cpool;
int tag;
tree name;
{
int j = find_utf8_constant (cpool, name);
int i;
for (i = cpool->count; --i > 0; )
{
if (cpool->tags[i] == tag && cpool->data[i] == j)
return i;
}
i = cpool->count;
set_constant_entry (cpool, i, tag, (jword) j);
return i;
}
int
find_class_constant (cpool, type)
CPool *cpool;
tree type;
{
return find_class_or_string_constant (cpool, CONSTANT_Class,
build_internal_class_name (type));
}
/* Find (or create) a CONSTANT_NameAndType matching NAME and TYPE.
Return its index in the constant pool CPOOL. */
int
find_name_and_type_constant (cpool, name, type)
CPool *cpool;
tree name;
tree type;
{
int name_index = find_utf8_constant (cpool, name);
int type_index = find_utf8_constant (cpool, build_java_signature (type));
return find_constant1 (cpool, CONSTANT_NameAndType,
(name_index << 16) | type_index);
}
/* Find (or create) a CONSTANT_Fieldref for DECL (a FIELD_DECL or VAR_DECL).
Return its index in the constant pool CPOOL. */
int
find_fieldref_index (cpool, decl)
CPool *cpool;
tree decl;
{
int class_index = find_class_constant (cpool, DECL_CONTEXT (decl));
int name_type_index
= find_name_and_type_constant (cpool, DECL_NAME (decl), TREE_TYPE (decl));
return find_constant1 (cpool, CONSTANT_Fieldref,
(class_index << 16) | name_type_index);
}
/* Find (or create) a CONSTANT_Methodref for DECL (a FUNCTION_DECL).
Return its index in the constant pool CPOOL. */
int
find_methodref_index (cpool, decl)
CPool *cpool;
tree decl;
{
int class_index = find_class_constant (cpool, DECL_CONTEXT (decl));
tree name = DECL_CONSTRUCTOR_P (decl) ? init_identifier_node
: DECL_NAME (decl);
int name_type_index
= find_name_and_type_constant (cpool, name, TREE_TYPE (decl));
/* Methodref or INterfacemethodRef - FIXME */
return find_constant1 (cpool, CONSTANT_Methodref,
(class_index << 16) | name_type_index);
}
#define PUT1(X) (*ptr++ = (X))
#define PUT2(X) (PUT1((X) >> 8), PUT1(X))
#define PUT4(X) (PUT2((X) >> 16), PUT2(X))
#define PUTN(P, N) (bcopy(P, ptr, N), ptr += (N))
/* Give the number of bytes needed in a .class file for the CPOOL
constant pool. Includes the 2-byte constant_pool_count. */
int
count_constant_pool_bytes (cpool)
CPool *cpool;
{
int size = 2;
int i = 1;
jword *datap = &cpool->data[1];;
for ( ; i < cpool->count; i++, datap++)
{
size++;
switch (cpool->tags[i])
{
case CONSTANT_NameAndType:
case CONSTANT_Fieldref:
case CONSTANT_Methodref:
case CONSTANT_InterfaceMethodref:
case CONSTANT_Float:
case CONSTANT_Integer:
size += 4;
break;
case CONSTANT_Class:
case CONSTANT_String:
size += 2;
break;
case CONSTANT_Long:
case CONSTANT_Double:
size += 4;
break;
case CONSTANT_Utf8:
{
tree t = (tree) *datap;
int len = IDENTIFIER_LENGTH (t);
size += len + 2;
}
break;
}
}
return size;
}
/* Write the constant pool CPOOL into BUFFER.
The length of BUFFER is LENGTH, which must match the needed length. */
void
write_constant_pool (cpool, buffer, length)
CPool *cpool;
unsigned char* buffer;
int length;
{
unsigned char* ptr = buffer;
int i = 1;
jword *datap = &cpool->data[1];
PUT2 (cpool->count);
for ( ; i < cpool->count; i++, datap++)
{
int tag = cpool->tags[i];
PUT1 (tag);
switch (tag)
{
case CONSTANT_NameAndType:
case CONSTANT_Fieldref:
case CONSTANT_Methodref:
case CONSTANT_InterfaceMethodref:
case CONSTANT_Float:
case CONSTANT_Integer:
PUT4 (*datap);
break;
case CONSTANT_Class:
case CONSTANT_String:
PUT2 (*datap);
break;
break;
case CONSTANT_Long:
case CONSTANT_Double:
PUT4(*datap);
i++;
datap++;
PUT4 (*datap);
break;
case CONSTANT_Utf8:
{
tree t = (tree) *datap;
int len = IDENTIFIER_LENGTH (t);
PUT2 (len);
PUTN (IDENTIFIER_POINTER (t), len);
}
break;
}
}
if (ptr != buffer + length)
fatal("internal error - incorrect constant pool");
}
CPool *outgoing_cpool;
/* If non-NULL, an ADDR_EXPR referencing a VAR_DECL containing
the constant data array for the current class. */
tree current_constant_pool_data_ref;
/* A Cache for build_int_2 (CONSTANT_XXX, 0). */
static tree tag_nodes[13];
tree
get_tag_node (tag)
int tag;
{
if (tag_nodes[tag] == NULL_TREE)
{
push_obstacks (&permanent_obstack, &permanent_obstack);
tag_nodes[tag] = build_int_2 (tag, 0);
pop_obstacks ();
}
return tag_nodes[tag];
}
/* Look for a constant pool entry that matches TAG and NAME.
Creates a new entry if not found.
TAG is one of CONSTANT_Utf8, CONSTANT_String or CONSTANT_Class.
NAME is an IDENTIFIER_NODE naming the Utf8 constant, string, or class.
Returns the index of the entry. */
int
alloc_name_constant (tag, name)
int tag;
tree name;
{
return find_constant1 (outgoing_cpool, tag, (jword) name);
}
/* Build an identifier for the internal name of reference type TYPE. */
tree
build_internal_class_name (type)
tree type;
{
tree name;
if (TYPE_ARRAY_P (type))
name = build_java_signature (type);
else
{
name = TYPE_NAME (type);
if (TREE_CODE (name) != IDENTIFIER_NODE)
name = DECL_NAME (name);
name = identifier_subst (name, "", '.', '/', "");
}
return name;
}
/* Look for a CONSTANT_Class entry for CLAS, creating a new one if needed. */
int
alloc_class_constant (clas)
tree clas;
{
return alloc_name_constant (CONSTANT_Class,
build_internal_class_name (clas));
}
/* Return a reference to the data array of the current constant pool. */
tree
build_constant_data_ref ()
{
if (current_constant_pool_data_ref == NULL_TREE)
{
tree decl;
tree decl_name = mangled_classname ("_CD_", current_class);
push_obstacks (&permanent_obstack, &permanent_obstack);
decl = build_decl (VAR_DECL, decl_name,
build_array_type (ptr_type_node,
one_elt_array_domain_type));
TREE_STATIC (decl) = 1;
make_decl_rtl (decl, NULL, 1);
pop_obstacks ();
current_constant_pool_data_ref
= build1 (ADDR_EXPR, ptr_type_node, decl);
}
return current_constant_pool_data_ref;
}
/* Get the pointer value at the INDEX'th element of the constant pool. */
tree
build_ref_from_constant_pool (index)
int index;
{
tree t = build_constant_data_ref ();
index *= int_size_in_bytes (ptr_type_node);
t = fold (build (PLUS_EXPR, ptr_type_node,
t, build_int_2 (index, 0)));
return build1 (INDIRECT_REF, ptr_type_node, t);
}
/* Build an initializer for the constants field of the current constal pool.
Should only be called at top-level, since it may emit declarations. */
tree
build_constants_constructor ()
{
tree tags_value, data_value;
tree cons;
tree tags_list = NULL_TREE;
tree data_list = NULL_TREE;
int i;
for (i = outgoing_cpool->count; --i > 0; )
{
tags_list
= tree_cons (NULL_TREE, get_tag_node (outgoing_cpool->tags[i]),
tags_list);
data_list
= tree_cons (NULL_TREE, build_utf8_ref ((tree)outgoing_cpool->data[i]),
data_list);
}
if (outgoing_cpool->count > 0)
{
tree index_type;
tree data_decl, tags_decl, tags_type;
tree max_index = build_int_2 (outgoing_cpool->count - 1, 0);
TREE_TYPE (max_index) = sizetype;
index_type = build_index_type (max_index);
/* Add dummy 0'th element of constant pool. */
tags_list = tree_cons (NULL_TREE, get_tag_node (0), tags_list);
data_list = tree_cons (NULL_TREE, null_pointer_node, data_list);
data_decl = TREE_OPERAND (build_constant_data_ref (), 0);
TREE_TYPE (data_decl) = build_array_type (ptr_type_node, index_type),
DECL_INITIAL (data_decl) = build (CONSTRUCTOR, TREE_TYPE (data_decl),
NULL_TREE, data_list);
DECL_SIZE (data_decl) = TYPE_SIZE (TREE_TYPE (data_decl));
rest_of_decl_compilation (data_decl, (char*) 0, 1, 0);
data_value = build_address_of (data_decl);
tags_type = build_array_type (unsigned_byte_type_node, index_type);
tags_decl = build_decl (VAR_DECL, mangled_classname ("_CT_",
current_class),
tags_type);
TREE_STATIC (tags_decl) = 1;
DECL_INITIAL (tags_decl) = build (CONSTRUCTOR, tags_type,
NULL_TREE, tags_list);
rest_of_decl_compilation (tags_decl, (char*) 0, 1, 0);
tags_value = build_address_of (tags_decl);
}
else
{
data_value = null_pointer_node;
tags_value = null_pointer_node;
}
START_RECORD_CONSTRUCTOR (cons, constants_type_node);
PUSH_FIELD_VALUE (cons, "size", build_int_2 (outgoing_cpool->count, 0));
PUSH_FIELD_VALUE (cons, "tags", tags_value);
PUSH_FIELD_VALUE (cons, "data", data_value);
FINISH_RECORD_CONSTRUCTOR (cons);
return cons;
}

24
gcc/java/convert.h Normal file
View file

@ -0,0 +1,24 @@
/* Definition of conversion functions.
Copyright (C) 1993 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC 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.
GNU CC 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* Written by Jeffrey Hsu <hsu@cygnus.com> */
extern tree convert_to_boolean PROTO ((tree, tree));
extern tree convert_to_char PROTO ((tree, tree));

1561
gcc/java/decl.c Normal file

File diff suppressed because it is too large Load diff

278
gcc/java/except.c Normal file
View file

@ -0,0 +1,278 @@
/* Handle exceptions for GNU compiler for the Java(TM) language.
Copyright (C) 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC 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.
GNU CC 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, 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 <stdio.h>
#include "config.h"
#include "tree.h"
#include "real.h"
#include "rtl.h"
#include "java-tree.h"
#include "javaop.h"
#include "java-opcodes.h"
#include "jcf.h"
#include "except.h"
#include "java-except.h"
#include "eh-common.h"
extern struct obstack permanent_obstack;
struct eh_range *current_method_handlers;
struct eh_range *current_try_block = NULL;
struct eh_range *eh_range_freelist = NULL;
/* These variables are used to speed up find_handler. */
static int cache_range_start, cache_range_end;
static struct eh_range *cache_range;
static struct eh_range *cache_next_child;
/* A dummy range that represents the entire method. */
struct eh_range whole_range;
/* Search for the most specific eh_range containing PC.
Assume PC is within RANGE.
CHILD is a list of children of RANGE such that any
previous children have end_pc values that are too low. */
static struct eh_range *
find_handler_in_range (pc, range, child)
int pc;
struct eh_range *range;
register struct eh_range *child;
{
for (; child != NULL; child = child->next_sibling)
{
if (pc < child->start_pc)
break;
if (pc <= child->end_pc)
return find_handler_in_range (pc, child, child->first_child);
}
cache_range = range;
cache_range_start = pc;
cache_next_child = child;
cache_range_end = child == NULL ? range->end_pc : child->start_pc;
return range;
}
/* Find the inner-most handler that contains PC. */
struct eh_range *
find_handler (pc)
int pc;
{
struct eh_range *h;
if (pc >= cache_range_start)
{
h = cache_range;
if (pc < cache_range_end)
return h;
while (pc >= h->end_pc)
{
cache_next_child = h->next_sibling;
h = h->outer;
}
}
else
{
h = &whole_range;
cache_next_child = h->first_child;
}
return find_handler_in_range (pc, h, cache_next_child);
}
#if 0
first_child;
next_sibling;
outer;
#endif
/* Recursive helper routine for add_handler. */
static int
link_handler (start_pc, end_pc, handler, type, outer)
int start_pc, end_pc;
tree handler;
tree type;
struct eh_range *outer;
{
struct eh_range **ptr;
if (start_pc < outer->start_pc || end_pc > outer->end_pc)
return 0; /* invalid or non-nested exception range */
if (start_pc == outer->start_pc && end_pc == outer->end_pc)
{
outer->handlers = tree_cons (type, handler, outer->handlers);
return 1;
}
ptr = &outer->first_child;
for (;; ptr = &(*ptr)->next_sibling)
{
if (*ptr == NULL || end_pc <= (*ptr)->start_pc)
{
struct eh_range *h = (struct eh_range *)
oballoc (sizeof (struct eh_range));
h->start_pc = start_pc;
h->end_pc = end_pc;
h->next_sibling = *ptr;
h->first_child = NULL;
h->outer = outer;
h->handlers = build_tree_list (type, handler);
*ptr = h;
return 1;
}
else if (start_pc < (*ptr)->end_pc)
return link_handler (start_pc, end_pc, handler, type, *ptr);
/* end_pc > (*ptr)->start_pc && start_pc >= (*ptr)->end_pc. */
}
}
/* Called to re-initialize the exception machinery for a new method. */
void
method_init_exceptions ()
{
whole_range.start_pc = 0;
whole_range.end_pc = DECL_CODE_LENGTH (current_function_decl) + 1;
whole_range.outer = NULL;
whole_range.first_child = NULL;
whole_range.next_sibling = NULL;
cache_range_start = 0xFFFFFF;
set_exception_lang_code (EH_LANG_Java);
set_exception_version_code (1);
}
int
add_handler (start_pc, end_pc, handler, type)
int start_pc, end_pc;
tree handler;
tree type;
{
return link_handler (start_pc, end_pc, handler, type, &whole_range);
}
/* if there are any handlers for this range, issue start of region */
void
expand_start_java_handler (range)
struct eh_range *range;
{
expand_eh_region_start ();
}
/* if there are any handlers for this range, isssue end of range,
and then all handler blocks */
void
expand_end_java_handler (range)
struct eh_range *range;
{
tree handler = range->handlers;
expand_start_all_catch ();
for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
{
tree type = TREE_PURPOSE (handler);
tree exp;
/* The "type" (metch_info) in a (Java) exception table is one:
* a) NULL - meaning match any type in a try-finally.
* b) a pointer to a (ccmpiled) class (low-order bit 0).
* c) a pointer to the Utf8Const name of the class, plus one
* (which yields a value with low-order bit 1). */
push_obstacks (&permanent_obstack, &permanent_obstack);
if (type == NULL_TREE)
exp = null_pointer_node;
else if (is_compiled_class (type))
exp = build_class_ref (type);
else
exp = fold (build (PLUS_EXPR, ptr_type_node,
build_utf8_ref (build_internal_class_name (type)),
size_one_node));
pop_obstacks ();
start_catch_handler (exp);
expand_goto (TREE_VALUE (handler));
}
expand_end_all_catch ();
}
/* Recursive helper routine for maybe_start_handlers. */
static void
check_start_handlers (range, pc)
struct eh_range *range;
int pc;
{
if (range != NULL_EH_RANGE && range->start_pc == pc)
{
check_start_handlers (range->outer, pc);
expand_start_java_handler (range);
}
}
struct eh_range *current_range;
/* Emit any start-of-try-range start at PC. */
void
maybe_start_try (pc)
int pc;
{
if (! doing_eh (1))
return;
current_range = find_handler (pc);
check_start_handlers (current_range, pc);
}
/* Emit any end-of-try-range end at PC. */
void
maybe_end_try (pc)
int pc;
{
if (! doing_eh (1))
return;
while (current_range != NULL_EH_RANGE && current_range->end_pc <= pc)
{
expand_end_java_handler (current_range);
current_range = current_range->outer;
}
}
/* Emit the handler labels and their code */
void
emit_handlers ()
{
if (catch_clauses)
{
rtx funcend = gen_label_rtx ();
emit_jump (funcend);
emit_insns (catch_clauses);
expand_leftover_cleanups ();
emit_label (funcend);
}
}

2283
gcc/java/expr.c Normal file

File diff suppressed because it is too large Load diff

959
gcc/java/gjavah.c Normal file
View file

@ -0,0 +1,959 @@
/* Program to write C++-suitable header files from a Java(TM) .class
file. This is similar to SUN's javah.
Copyright (C) 1996, 1998 Free Software Foundation, Inc.
This program 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.
This program 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, 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. */
/* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
#include <stdio.h>
#include "jcf.h"
#ifdef __STDC__
#include <stdlib.h>
#endif
#include <math.h>
/* The output file. */
FILE *out = NULL;
/* Nonzero on failure. */
static int found_error = 0;
/* Directory to place resulting files in. Set by -d option. */
char *output_directory = "";
char *output_file = NULL;
/* Directory to place temporary file. Set by -td option. Currently unused. */
char *temp_directory = "/tmp";
/* Number of friend functions we have to declare. */
static int friend_count;
/* A class can optionally have a `friend' function declared. If
non-NULL, this is that function. */
static char **friend_specs = NULL;
/* Number of lines we are prepending before the class. */
static int prepend_count;
/* We can prepend extra lines before the class's start. */
static char **prepend_specs = NULL;
/* Number of lines we are appending at the end of the class. */
static int add_count;
/* We can append extra lines just before the class's end. */
static char **add_specs = NULL;
/* Number of lines we are appending after the class. */
static int append_count;
/* We can append extra lines after the class's end. */
static char **append_specs = NULL;
int verbose = 0;
int stubs = 0;
struct JCF *current_jcf;
struct JCF *main_jcf;
/* This holds access information for the last field we examined. They
let us generate "private:", "public:", and "protected:" properly.
If 0 then we haven't previously examined any field. */
static JCF_u2 last_access;
#define ACC_VISIBILITY (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED)
int seen_fields = 0;
static void print_field_info PROTO ((FILE *, JCF*, int, int, JCF_u2));
static void print_method_info PROTO ((FILE *, JCF*, int, int, JCF_u2));
static void print_c_decl PROTO ((FILE*, JCF*, int, int, JCF_u2, int));
JCF_u2 current_field_name;
JCF_u2 current_field_value;
JCF_u2 current_field_signature;
JCF_u2 current_field_flags;
#define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
( current_field_name = (NAME), current_field_signature = (SIGNATURE), \
current_field_flags = (ACCESS_FLAGS), current_field_value = 0)
#define HANDLE_END_FIELD() \
print_field_info (out, jcf, current_field_name, current_field_signature, \
current_field_flags);
#define HANDLE_CONSTANTVALUE(VALUEINDEX) current_field_value = (VALUEINDEX)
#define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
print_method_info (out, jcf, NAME, SIGNATURE, ACCESS_FLAGS)
#include "jcf-reader.c"
/* Some useful constants. */
#define F_NAN_MASK 0x7f800000
#define D_NAN_MASK 0x7ff0000000000000LL
/* Return 1 if F is not Inf or NaN. */
static int
java_float_finite (f)
jfloat f;
{
int32 *ip = (int32 *) &f;
/* We happen to know that F_NAN_MASK will match all NaN values, and
also positive and negative infinity. That's why we only need one
test here. See The Java Language Specification, section 20.9. */
return (*ip & F_NAN_MASK) != F_NAN_MASK;
}
/* Return 1 if D is not Inf or NaN. */
static int
java_double_finite (d)
jdouble d;
{
int64 *ip = (int64 *) &d;
/* Now check for all NaNs. */
return (*ip & D_NAN_MASK) != D_NAN_MASK;
}
void
DEFUN(print_name, (stream, jcf, name_index),
FILE* stream AND JCF* jcf AND int name_index)
{
if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
fprintf (stream, "<not a UTF8 constant>");
else
jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf, name_index),
JPOOL_UTF_LENGTH (jcf, name_index));
}
/* Print base name of class. The base name is everything after the
final separator. */
static void
print_base_classname (stream, jcf, index)
FILE *stream;
JCF *jcf;
int index;
{
int name_index = JPOOL_USHORT1 (jcf, index);
int i, len;
unsigned char *s, *p, *limit;
s = JPOOL_UTF_DATA (jcf, name_index);
len = JPOOL_UTF_LENGTH (jcf, name_index);
limit = s + len;
p = s;
while (s < limit)
{
int c = UTF8_GET (s, limit);
if (c == '/')
p = s;
}
while (p < limit)
{
int ch = UTF8_GET (p, limit);
if (ch == '/')
fputs ("::", stream);
else
jcf_print_char (stream, ch);
}
}
/* Return 0 if NAME is equal to STR, nonzero otherwise. */
static int
utf8_cmp (str, length, name)
unsigned char *str;
int length;
char *name;
{
unsigned char *limit = str + length;
int i;
for (i = 0; name[i]; ++i)
{
int ch = UTF8_GET (str, limit);
if (ch != name[i])
return 1;
}
return str != limit;
}
/* Generate an access control keyword based on FLAGS. Returns 0 if
FLAGS matches the saved access information, nonzero otherwise. */
static void
generate_access (stream, flags)
FILE *stream;
JCF_u2 flags;
{
/* FIXME: Java's "protected" and "no access specifier" modes don't
actually map to C++ "protected". That's how we map them for now,
though. */
if (! (flags & ACC_VISIBILITY))
flags = ACC_PROTECTED;
if ((flags & ACC_VISIBILITY) == last_access)
return;
last_access = (flags & ACC_VISIBILITY);
switch (last_access)
{
case ACC_PUBLIC:
fputs ("public:\n", stream);
break;
case ACC_PRIVATE:
fputs ("private:\n", stream);
break;
case ACC_PROTECTED:
fputs ("protected:\n", stream);
break;
default:
found_error = 1;
fprintf (stream, "#error unrecognized visibility %d\n",
(flags & ACC_VISIBILITY));
break;
}
}
static void
DEFUN(print_field_info, (stream, jcf, name_index, sig_index, flags),
FILE *stream AND JCF* jcf
AND int name_index AND int sig_index AND JCF_u2 flags)
{
if (flags & ACC_FINAL)
{
if (current_field_value > 0)
{
jlong num;
char buffer[25];
generate_access (stream, flags);
switch (JPOOL_TAG (jcf, current_field_value))
{
case CONSTANT_Integer:
fputs (" static const jint ", out);
print_name (out, jcf, name_index);
fputs (" = ", out);
num = JPOOL_INT (jcf, current_field_value);
format_int (buffer, num, 10);
fprintf (out, "%sL;\n", buffer);
break;
case CONSTANT_Long:
fputs (" static const jlong ", out);
print_name (out, jcf, name_index);
fputs (" = ", out);
num = JPOOL_LONG (jcf, current_field_value);
format_int (buffer, num, 10);
fprintf (out, "%sLL;\n", buffer);
break;
case CONSTANT_Float:
{
jfloat fnum = JPOOL_FLOAT (jcf, current_field_value);
fputs (" static const jfloat ", out);
print_name (out, jcf, name_index);
if (! java_float_finite (fnum))
fputs (";\n", out);
else
fprintf (out, " = %.10g;\n", fnum);
}
break;
case CONSTANT_Double:
{
jdouble dnum = JPOOL_DOUBLE (jcf, current_field_value);
fputs (" static const jdouble ", out);
print_name (out, jcf, name_index);
if (! java_double_finite (dnum))
fputs (";\n", out);
else
fprintf (out, " = %.17g;\n", dnum);
}
break;
default:
fprintf(out, " <<inappropriate constant type>>\n");
}
return;
}
}
generate_access (stream, flags);
fputs (" ", out);
if (flags & ACC_STATIC)
fputs ("static ", out);
print_c_decl (out, jcf, name_index, sig_index, flags, 0);
fputs (";\n", out);
if (! (flags & ACC_STATIC))
seen_fields++;
}
static void
DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
FILE *stream AND JCF* jcf
AND int name_index AND int sig_index AND JCF_u2 flags)
{
unsigned char *str;
int length, is_init = 0;
if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
fprintf (stream, "<not a UTF8 constant>");
str = JPOOL_UTF_DATA (jcf, name_index);
length = JPOOL_UTF_LENGTH (jcf, name_index);
if (str[0] == '<')
{
/* Ignore internally generated methods like <clinit>. However,
treat <init> as a constructor. */
if (! utf8_cmp (str, length, "<init>"))
is_init = 1;
else
return;
}
/* We can't generate a method whose name is a C++ reserved word.
For now the only problem has been `delete'; add more here as
required. FIXME: we need a better solution than just ignoring
the method. */
if (! utf8_cmp (str, length, "delete"))
return;
generate_access (stream, flags);
fputs (" ", out);
if ((flags & ACC_STATIC))
fputs ("static ", out);
else if (! (flags & ACC_FINAL) && ! (jcf->access_flags & ACC_FINAL))
{
/* Don't print `virtual' if we have a constructor. */
if (! is_init)
fputs ("virtual ", out);
}
print_c_decl (out, jcf, name_index, sig_index, flags, is_init);
/* FIXME: it would be nice to decompile small methods here. That
would allow for inlining. */
fprintf(out, ";\n");
}
static void
DEFUN(print_c_decl, (stream, jcf, name_index, signature_index, flags, is_init),
FILE* stream AND JCF* jcf
AND int name_index AND int signature_index AND JCF_u2 flags
AND int is_init)
{
if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
fprintf (stream, "<not a UTF8 constant>");
else
{
int length = JPOOL_UTF_LENGTH (jcf, signature_index);
unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
register unsigned char *str = str0;
unsigned char *limit = str + length;
int j;
char *ctype;
int need_space = 0;
int is_method = str[0] == '(';
if (is_method)
{
/* Skip to the return signature, and print that first.
However, don't do this is we are printing a construtcor.
*/
if (is_init)
{
str = str0 + 1;
/* FIXME: Most programmers love Celtic knots because
they see their own code in the interconnected loops.
That is, this is spaghetti. */
goto have_constructor;
}
else
{
while (str < limit)
{
int ch = *str++;
if (ch == ')')
break;
}
}
}
again:
while (str < limit)
{
switch (str[0])
{
case '[':
for (str++; str < limit && *str >= '0' && *str <= '9'; str++)
;
switch (*str)
{
case 'B': ctype = "jbyteArray"; goto printit;
case 'C': ctype = "jcharArray"; goto printit;
case 'D': ctype = "jdoubleArray"; goto printit;
case 'F': ctype = "jfloatArray"; goto printit;
case 'I': ctype = "jintArray"; goto printit;
case 'S': ctype = "jshortArray"; goto printit;
case 'J': ctype = "jlongArray"; goto printit;
case 'Z': ctype = "jbooleanArray"; goto printit;
case '[': ctype = "jobjectArray"; goto printit;
case 'L':
/* We have to generate a reference to JArray here,
so that our output matches what the compiler
does. */
++str;
fputs ("JArray<", out);
while (str < limit && *str != ';')
{
int ch = UTF8_GET (str, limit);
if (ch == '/')
fputs ("::", stream);
else
jcf_print_char (stream, ch);
}
fputs (" *> *", out);
need_space = 0;
++str;
break;
default:
fprintf (stderr, "unparseable signature `%s'\n", str0);
found_error = 1;
ctype = "???"; goto printit;
}
break;
case '(':
fputc (*str++, stream);
continue;
case ')':
fputc (*str++, stream);
/* the return signature was printed in the first pass. */
return;
case 'B': ctype = "jbyte"; goto printit;
case 'C': ctype = "jchar"; goto printit;
case 'D': ctype = "jdouble"; goto printit;
case 'F': ctype = "jfloat"; goto printit;
case 'I': ctype = "jint"; goto printit;
case 'J': ctype = "jlong"; goto printit;
case 'S': ctype = "jshort"; goto printit;
case 'Z': ctype = "jboolean"; goto printit;
case 'V': ctype = "void"; goto printit;
case 'L':
++str;
while (*str && *str != ';')
{
int ch = UTF8_GET (str, limit);
if (ch == '/')
fputs ("::", stream);
else
jcf_print_char (stream, ch);
}
fputs (" *", stream);
if (*str == ';')
str++;
need_space = 0;
break;
default:
need_space = 1;
jcf_print_char (stream, *str++);
break;
printit:
str++;
need_space = 1;
fputs (ctype, stream);
break;
}
if (is_method && str < limit && *str != ')')
fputs (", ", stream);
}
have_constructor:
if (name_index)
{
if (need_space)
fprintf (stream, " ");
/* Declare constructors specially. */
if (is_init)
print_base_classname (stream, jcf, jcf->this_class);
else
print_name (stream, jcf, name_index);
}
if (is_method)
{
fputs (" (", stream);
/* Go to beginning, skipping '('. */
str = str0 + 1;
goto again; /* To handle argument signatures. */
}
}
}
int
DEFUN(print_mangled_classname, (stream, jcf, prefix, index),
FILE *stream AND JCF *jcf AND char *prefix AND int index)
{
int name_index = JPOOL_USHORT1 (jcf, index);
fputs (prefix, stream);
jcf_print_utf8_replace (out,
JPOOL_UTF_DATA (jcf, name_index),
JPOOL_UTF_LENGTH (jcf, name_index),
'/', '_');
}
/* Print PREFIX, then a class name in C++ format. If the name refers
to an array, ignore it and don't print PREFIX. Returns 1 if
something was printed, 0 otherwise. */
static int
print_cxx_classname (stream, prefix, jcf, index)
FILE *stream;
char *prefix;
JCF *jcf;
int index;
{
int name_index = JPOOL_USHORT1 (jcf, index);
int i, len, c;
unsigned char *s, *p, *limit;
s = JPOOL_UTF_DATA (jcf, name_index);
len = JPOOL_UTF_LENGTH (jcf, name_index);
limit = s + len;
/* Explicitly omit arrays here. */
p = s;
c = UTF8_GET (p, limit);
if (c == '[')
return 0;
fputs (prefix, stream);
while (s < limit)
{
c = UTF8_GET (s, limit);
if (c == '/')
fputs ("::", stream);
else
jcf_print_char (stream, c);
}
return 1;
}
int written_class_count = 0;
/* Return name of superclass. If LEN is not NULL, fill it with length
of name. */
static unsigned char *
super_class_name (derived_jcf, len)
JCF *derived_jcf;
int *len;
{
int supername_index = JPOOL_USHORT1 (derived_jcf, derived_jcf->super_class);
int supername_length = JPOOL_UTF_LENGTH (derived_jcf, supername_index);
unsigned char *supername = JPOOL_UTF_DATA (derived_jcf, supername_index);
if (len)
*len = supername_length;
return supername;
}
/* Print declarations for all classes required by this class. FIXME:
the current implementation just prints every class name from the
constant pool. This is too much. We really only need to print a
declaration for each class which is the type of a return value, a
field, or an argument. */
static void
print_class_decls (out, jcf)
FILE *out;
JCF *jcf;
{
int i, seen_one = 0;
for (i = 1; i < JPOOL_SIZE (jcf); ++i)
{
int kind = JPOOL_TAG (jcf, i);
if (kind == CONSTANT_Class)
{
if (print_cxx_classname (out, "class ", jcf, i))
fputs (";\n", out);
seen_one = 1;
}
}
if (seen_one)
fputs ("\n", out);
}
static void
DEFUN(process_file, (file, out),
JCF *jcf AND FILE *out)
{
int code, i;
current_jcf = main_jcf = jcf;
last_access = 0;
if (jcf_parse_preamble (jcf) != 0)
{
fprintf (stderr, "Not a valid Java .class file.\n");
found_error = 1;
return;
}
/* Parse and possibly print constant pool */
code = jcf_parse_constant_pool (jcf);
if (code != 0)
{
fprintf (stderr, "error while parsing constant pool\n");
found_error = 1;
return;
}
code = verify_constant_pool (jcf);
if (code > 0)
{
fprintf (stderr, "error in constant pool entry #%d\n", code);
found_error = 1;
return;
}
jcf_parse_class (jcf);
if (written_class_count++ == 0)
fputs ("// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*-\n\n",
out);
print_mangled_classname (out, jcf, "#ifndef __", jcf->this_class);
fprintf (out, "__\n");
print_mangled_classname (out, jcf, "#define __", jcf->this_class);
fprintf (out, "__\n\n");
if (jcf->super_class)
{
int super_length;
unsigned char *supername = super_class_name (jcf, &super_length);
fputs ("#include <", out);
jcf_print_utf8 (out, supername, super_length);
fputs (".h>\n", out);
/* FIXME: If our superclass is Object, then we include
java-array.h. The right thing to do here is look at all the
methods and fields and see if an array is in use. Only then
would we need to include java-array.h. */
if (! utf8_cmp (supername, super_length, "java/lang/Object"))
fputs ("#include <java-array.h>\n", out);
fputs ("\n", out);
}
print_class_decls (out, jcf);
for (i = 0; i < prepend_count; ++i)
fprintf (out, "%s\n", prepend_specs[i]);
if (prepend_count > 0)
fputc ('\n', out);
if (! print_cxx_classname (out, "class ", jcf, jcf->this_class))
{
fprintf (stderr, "class is of array type\n");
found_error = 1;
return;
}
if (jcf->super_class)
{
if (! print_cxx_classname (out, " : public ", jcf, jcf->super_class))
{
fprintf (stderr, "base class is of array type\n");
found_error = 1;
return;
}
}
fputs ("\n{\n", out);
/* We make a single pass over the file, printing methods and fields
as we see them. We have to list the methods in the same order
that they appear in the class file, so that the Java and C++
vtables have the same layout. */
jcf_parse_fields (jcf);
jcf_parse_methods (jcf);
jcf_parse_final_attributes (jcf);
/* Generate friend decl if we still must. */
for (i = 0; i < friend_count; ++i)
fprintf (out, " friend %s\n", friend_specs[i]);
/* Generate extra declarations. */
if (add_count > 0)
fputc ('\n', out);
for (i = 0; i < add_count; ++i)
fprintf (out, " %s\n", add_specs[i]);
fputs ("};\n", out);
if (append_count > 0)
fputc ('\n', out);
for (i = 0; i < append_count; ++i)
fprintf (out, "%s\n", append_specs[i]);
print_mangled_classname (out, jcf, "\n#endif /* __", jcf->this_class);
fprintf (out, "__ */\n");
}
static void
usage ()
{
fprintf (stderr, "gjavah: no classes specified\n");
exit (1);
}
static void
help ()
{
printf ("Usage: gjavah [OPTION]... CLASS...\n\n");
printf ("Generate C++ header files from .class files\n\n");
printf (" --classpath PATH Set path to find .class files\n");
printf (" -d DIRECTORY Set output directory name\n");
printf (" --help Print this help, then exit\n");
printf (" -o FILE Set output file name\n");
printf (" -td DIRECTORY Set temporary directory name\n");
printf (" -v, --verbose Print extra information while running\n");
printf (" --version Print version number, then exit\n");
/* FIXME: print bug-report information. */
exit (0);
}
static void
no_argument (opt)
char *opt;
{
fprintf (stderr, "gjavah: no argument given for option `%s'\n", opt);
exit (1);
}
static void
version ()
{
/* FIXME: use version.c? */
printf ("gjavah (GNU gcc) 0.0\n\n");
printf ("Copyright (C) 1998 Free Software Foundation, Inc.\n");
printf ("This is free software; see the source for copying conditions. There is NO\n");
printf ("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
exit (0);
}
int
DEFUN(main, (argc, argv),
int argc AND char** argv)
{
JCF jcf;
int argi;
if (argc <= 1)
usage ();
for (argi = 1; argi < argc; argi++)
{
char *arg = argv[argi];
if (arg[0] != '-' || ! strcmp (arg, "--"))
break;
/* Just let all arguments be given in either "-" or "--" form. */
if (arg[1] == '-')
++arg;
if (strcmp (arg, "-o") == 0)
{
if (argi + 1 < argc)
output_file = argv[++argi];
else
no_argument (argv[argi]);
}
else if (strcmp (arg, "-d") == 0)
{
if (argi + 1 < argc)
output_directory = argv[++argi];
else
no_argument (argv[argi]);
}
else if (strcmp (arg, "-td") == 0)
{
if (argi + 1 < argc)
temp_directory = argv[++argi];
else
no_argument (argv[argi]);
}
else if (strcmp (arg, "-prepend") == 0)
{
if (argi + 1 < argc)
{
if (prepend_count == 0)
prepend_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
prepend_specs[prepend_count++] = argv[++argi];
}
else
no_argument (argv[argi]);
}
else if (strcmp (arg, "-friend") == 0)
{
if (argi + 1 < argc)
{
if (friend_count == 0)
friend_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
friend_specs[friend_count++] = argv[++argi];
}
else
no_argument (argv[argi]);
}
else if (strcmp (arg, "-add") == 0)
{
if (argi + 1 < argc)
{
if (add_count == 0)
add_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
add_specs[add_count++] = argv[++argi];
}
else
no_argument (argv[argi]);
}
else if (strcmp (arg, "-append") == 0)
{
if (argi + 1 < argc)
{
if (append_count == 0)
append_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
append_specs[append_count++] = argv[++argi];
}
else
no_argument (argv[argi]);
}
else if (strcmp (arg, "-classpath") == 0)
{
if (argi + 1 < argc)
classpath = argv[++argi];
else
no_argument (argv[argi]);
}
else if (strcmp (arg, "-verbose") == 0 || strcmp (arg, "-v") == 0)
verbose++;
else if (strcmp (arg, "-stubs") == 0)
stubs++;
else if (strcmp (arg, "-help") == 0)
help ();
else if (strcmp (arg, "-version") == 0)
version ();
else
{
fprintf (stderr, "%s: illegal argument\n", argv[argi]);
exit (1);
}
}
if (argi == argc)
usage ();
if (classpath == NULL)
{
classpath = (char *) getenv ("CLASSPATH");
if (classpath == NULL)
classpath = "";
}
for (; argi < argc; argi++)
{
char *classname = argv[argi];
char *classfile_name, *current_output_file;
if (verbose)
fprintf (stderr, "Processing %s\n", classname);
classfile_name = find_class (classname, strlen (classname), &jcf, 1);
if (classfile_name == NULL)
{
fprintf (stderr, "%s: no such class\n", classname);
exit (1);
}
if (verbose)
fprintf (stderr, "Found in %s\n", classfile_name);
if (output_file)
{
if (strcmp (output_file, "-") == 0)
out = stdout;
else if (out == NULL)
out = fopen (output_file, "w");
if (out == NULL)
{
perror (output_file);
exit (1);
}
current_output_file = output_file;
}
else
{
int dir_len = strlen (output_directory);
int i, classname_length = strlen (classname);
current_output_file = (char*) ALLOC (dir_len + classname_length + 4);
strcpy (current_output_file, output_directory);
if (dir_len > 0 && output_directory[dir_len-1] != '/')
current_output_file[dir_len++] = '/';
for (i = 0; classname[i] != '\0'; i++)
{
char ch = classname[i];
if (ch == '.')
ch = '/';
current_output_file[dir_len++] = ch;
}
strcpy (current_output_file+dir_len, ".h");
out = fopen (current_output_file, "w");
if (out == NULL)
{
perror (current_output_file);
exit (1);
}
}
process_file (&jcf, out);
JCF_FINISH (&jcf);
if (current_output_file != output_file)
free (current_output_file);
}
if (out != NULL && out != stdout)
fclose (out);
return found_error;
}
/* TODO:
* Do whatever the javah -stubs flag does.
* Emit "structure forward declarations" when needed.
* Generate C headers, like javah
*/

67
gcc/java/java-except.h Normal file
View file

@ -0,0 +1,67 @@
/* Definitions for exception handling for use by the GNU compiler
for the Java(TM) language compiler.
Copyright (C) 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC 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.
GNU CC 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, 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. */
struct eh_range
{
/* The (byte-code PC) range of the handled block. */
int start_pc;
int end_pc;
/* A list of handlers. For each element in the list,
the TREE_PURPOSE is the handled class (NULL_EXPR for a finally block),
and the TREE_VALUE is the LABEL_DECL of the handler. */
tree handlers;
/* Surrunding handler, if any. */
struct eh_range *outer;
/* The first child range. It is is nested inside this range
(i.e. this.start_pc <= first_child.end_pc
&& this.end_pc >= first_child.end_pc).
The children are linked together using next_sibling, and are sorted
by increasing start_pc and end_pc (we do not support non-nested
overlapping ranges). */
struct eh_range *first_child;
/* The next child of outer, in address order. */
struct eh_range *next_sibling;
#if 0
/* Next handler, sorted by ascending start_pc then descending end_pc. */
tree next;
#endif
};
/* A dummy range that represents the entire method. */
extern struct eh_range whole_range;
#define NULL_EH_RANGE (&whole_range)
extern struct eh_range * find_handler PROTO ((int));
extern void method_init_exceptions PROTO ((void));
extern void emit_handlers PROTO ((void));

5
gcc/java/java-opcodes.h Normal file
View file

@ -0,0 +1,5 @@
enum java_opcode {
#define JAVAOP(NAME, CODE, KIND, TYPE, VALUE) OPCODE_##NAME = CODE,
#include "javaop.def"
#undef JAVAOP
};

12
gcc/java/java-tree.def Normal file
View file

@ -0,0 +1,12 @@
/* Shift right, logical. */
DEFTREECODE (URSHIFT_EXPR, "urshift_expr", "2", 2)
/* Return -1, 0, 1 depending on whether the first argument is
less, equal, or greater to the second argument. */
DEFTREECODE (COMPARE_EXPR, "compare_expr", "2", 2)
/* Same as COMPARE_EXPR, but if either value is NaN, the result is -1. */
DEFTREECODE (COMPARE_L_EXPR, "compare_l_expr", "2", 2)
/* Same as COMPARE_EXPR, but if either value is NaN, the result is 1. */
DEFTREECODE (COMPARE_G_EXPR, "compare_g_expr", "2", 2)

720
gcc/java/java-tree.h Normal file
View file

@ -0,0 +1,720 @@
/* Definitions for parsing and type checking for the GNU compiler for
the Java(TM) language.
Copyright (C) 1997, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC 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.
GNU CC 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, 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. */
/* Hacked by Per Bothner <bothner@cygnus.com> February 1996. */
/* Java language-specific tree codes. */
#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) SYM,
enum java_tree_code {
__DUMMY = LAST_AND_UNUSED_TREE_CODE,
#include "java-tree.def"
LAST_JAVA_TREE_CODE
};
#undef DEFTREECODE
struct JCF;
/* Usage of TREE_LANG_FLAG_?:
0: IS_A_SINGLE_IMPORT_CLASSFILE_NAME_P (in IDENTIFIER_NODE)
RESOLVE_EXPRESSION_NAME_P (in EXPR_WITH_FILE_LOCATION)
IS_FOR_LOOP_P (in LOOP_EXPR)
1: CLASS_HAS_SUPER_FLAG (in TREE_VEC).
IS_A_CLASSFILE_NAME (in IDENTIFIER_NODE)
COMPOUND_ASSIGN_P (in EXPR (binop_*))
2: RETURN_MAP_ADJUSTED (in TREE_VEC).
QUALIFIED_P (in IDENTIFIER_NODE)
PRIMARY_P (in EXPR_WITH_FILE_LOCATION)
MODIFY_EXPR_FROM_INITIALIZATION_P (in MODIFY_EXPR)
3: IS_AN_IMPORT_ON_DEMAND_P (in IDENTIFIER_NODE)
RESOLVE_PACKAGE_NAME_P (in EXPR_WITH_FILE_LOCATION)
4: RESOLVE_TYPE_NAME_P (in EXPR_WITH_FILE_LOCATION)
5: IS_BREAK_STMT_P (in EXPR_WITH_FILE_LOCATION)
Usage of TYPE_LANG_FLAG_?:
1: TYPE_ARRAY_P (in RECORD_TYPE).
2: CLASS_LOADED_P (in RECORD_TYPE).
3: CLASS_FROM_SOURCE_P (in RECORD_TYPE).
4: CLASS_P (in RECORD_TYPE).
Usage of DECL_LANG_FLAG_?:
1: METHOD_PUBLIC (in FUNCTION_DECL).
FIELD_PUBLIC (in FIELD_DECL).
CLASS_PUBLIC (in TYPE_DECL).
2: METHOD_STATIC (in FUNCTION_DECL).
(But note that FIELD_STATIC uses TREE_STATIC!)
CLASS_COMPLETE_P (in TYPE_DECL)
3: METHOD_FINAL (in FUNCTION_DECL)
FIELD_FINAL (in FIELD_DECL)
CLASS_FINAL (in TYPE_DECL)
4: METHOD_SYNCHRONIZED (in FUNCTION_DECL).
LABEL_IN_SUBR (in LABEL_DECL)
CLASS_INTERFACE (in TYPE_DECL)
FIELD_VOLATILE (int FIELD_DECL)
5: METHOD_ABSTRACT (in FUNCTION_DECL).
LABEL_IS_SUBR_START (in LABEL_DECL)
CLASS_ABSTRACT (in TYPE_DECL)
FIELD_TRANSIENT (in FIELD_DECL)
6: METHOD_TRANSIENT (in FUNCTION_DECL)
LABEL_CHANGED (in LABEL_DECL)
CLASS_SUPER (in TYPE_DECL, ACC_SUPER flag)
INITIALIZED_P (in FIELD_DECL, VAR_DECL, PARM_DECL)
7: DECL_CONSTRUCTOR_P (in FUNCTION_DECL)
*/
/* True if the class whose TYPE_BINFO this is has a superclass.
(True of all classes except Object.) */
#define CLASS_HAS_SUPER_FLAG(BINFO) TREE_LANG_FLAG_1(BINFO)
#define CLASS_HAS_SUPER(TYPE) CLASS_HAS_SUPER_FLAG (TYPE_BINFO (TYPE))
/* Return the supertype of class TYPE, or NULL_TREE is it has none. */
#define CLASSTYPE_SUPER(TYPE) (CLASS_HAS_SUPER (TYPE) ? \
BINFO_TYPE (TREE_VEC_ELT (TYPE_BINFO_BASETYPES (TYPE), 0)) : NULL_TREE)
/* True if the class we are compiling is a .java source file;
false if it is a .class bytecode file. */
extern int compiling_from_source;
/* The class defined by the actual (main) file we are compiling. */
extern tree main_class;
/* The class we are currently processing. */
extern tree current_class;
/* Nonzero if we want to automatically do array bounds checking;
on by default. Use -fno-bounds-check to disable. */
extern int flag_bounds_check;
/* Nonzero if we should make is_compiled_class always return 1 for
appropriate classes that we're referencing. */
extern int flag_assume_compiled;
extern int flag_emit_class_files;
/* The Java .class file that provides main_class; the main input file. */
extern struct JCF main_jcf[1], *current_jcf;
typedef struct CPool constant_pool;
#define CONSTANT_ResolvedFlag 16
/* The cpool->data[i] for a ResolvedString points to a STRING_CST. */
#define CONSTANT_ResolvedString (CONSTANT_String+CONSTANT_ResolvedFlag)
/* The cpool->data[i] for a ResolvedClass points to a RECORD_TYPE. */
#define CONSTANT_ResolvedClass (CONSTANT_Class+CONSTANT_ResolvedFlag)
#define CPOOL_UTF(CPOOL, INDEX) ((tree) (CPOOL)->data[INDEX])
/* A NameAndType constant is represented as a TREE_LIST.
The type is the signature string (as an IDENTIFIER_NODE). */
#define NAME_AND_TYPE_NAME(CPOOL, IDX) \
CPOOL_UTF(CPOOL, CPOOL_USHORT1(CPOOL, IDX))
#define NAME_AND_TYPE_SIGNATURE(CPOOL, IDX) \
CPOOL_UTF(CPOOL, CPOOL_USHORT2(CPOOL, IDX))
/* A FieldRef, MethodRef or InterfaceMethodRef constant
is represented as a TREE_LIST. */
#define COMPONENT_REF_CLASS_INDEX(CPOOL, IDX) CPOOL_USHORT1(CPOOL, IDX)
#define COMPONENT_REF_NAME_AND_TYPE(CPOOL, IDX) CPOOL_USHORT2(CPOOL, IDX)
#define COMPONENT_REF_NAME(CPOOL, IDX) \
NAME_AND_TYPE_NAME (CPOOL, COMPONENT_REF_NAME_AND_TYPE(CPOOL, IDX))
#define COMPONENT_REF_SIGNATURE(CPOOL, IDX) \
NAME_AND_TYPE_SIGNATURE (CPOOL, COMPONENT_REF_NAME_AND_TYPE(CPOOL, IDX))
/* "Promoted types" that are used for primitive types smaller
than int. We could use int_type_node, but then we would lose
type information (such as needed for debugging). */
extern tree promoted_byte_type_node;
extern tree promoted_short_type_node;
extern tree promoted_char_type_node;
extern tree promoted_boolean_type_node;
extern tree byte_type_node;
extern tree short_type_node;
extern tree int_type_node;
extern tree long_type_node;
extern tree unsigned_byte_type_node;
extern tree unsigned_short_type_node;
extern tree unsigned_int_type_node;
extern tree unsigned_long_type_node;
extern tree boolean_type_node;
extern tree char_type_node;
extern tree float_type_node;
extern tree double_type_node;
extern tree object_type_node;
extern tree object_ptr_type_node;
extern tree string_type_node;
extern tree throwable_type_node;
extern tree byte_array_type_node;
extern tree short_array_type_node;
extern tree int_array_type_node;
extern tree long_array_type_node;
extern tree boolean_array_type_node;
extern tree char_array_type_node;
extern tree double_array_type_node;
extern tree float_array_type_node;
extern tree array_array_type_node;
extern tree object_array_type_node;
extern tree string_array_type_node;
extern tree TYPE_identifier_node; /* "TYPE" */
extern tree init_identifier_node; /* "<init>" */
extern tree clinit_identifier_node; /* "<clinit>" */
extern tree void_signature_node; /* "()V" */
extern tree finalize_identifier_node; /* "finalize" */
extern tree length_identifier_node; /* "length" */
extern tree this_identifier_node; /* "this" */
extern tree super_identifier_node; /* "super" */
extern tree one_elt_array_domain_type;
extern tree void_type_node;
extern tree ptr_type_node;
/* The type of the return address of a subroutine. */
extern tree return_address_type_node;
/* Nodes for boolean constants TRUE and FALSE. */
extern tree boolean_true_node, boolean_false_node;
/* Integer constants not declared in tree.h. */
extern tree integer_negative_one_node;
extern tree integer_two_node;
extern tree integer_four_node;
/* The type for struct methodtable. */
extern tree methodtable_type;
extern tree methodtable_ptr_type;
extern tree utf8const_type;
extern tree utf8const_ptr_type;
extern tree class_type_node;
extern tree class_ptr_type;
extern tree field_type_node;
extern tree constants_type_node;
extern tree dtable_type, dtable_ptr_type;
extern tree field_ptr_type_node;
extern tree field_info_union_node;
extern tree method_type_node;
extern tree method_ptr_type_node;
#define nativecode_ptr_type_node ptr_type_node
/* References to internal libjava functions we use. */
extern tree alloc_object_node;
extern tree soft_instanceof_node;
extern tree soft_checkcast_node;
extern tree soft_initclass_node;
extern tree soft_newarray_node;
extern tree soft_anewarray_node;
extern tree soft_multianewarray_node;
extern tree soft_badarrayindex_node;
extern tree throw_node;
extern tree soft_checkarraystore_node;
extern tree soft_monitorenter_node;
extern tree soft_monitorexit_node;
extern tree soft_lookupinterfacemethod_node;
extern tree soft_fmod_node;
extern tree access_flags_type_node;
extern tree class_dtable_decl;
/* They need to be reset before processing each class */
extern struct CPool *outgoing_cpool;
extern tree current_constant_pool_data_ref;
struct lang_identifier
{
struct tree_identifier ignore;
tree global_value, local_value;
/* If non-NULL: An ADDR_REF to a VAR_DECL that contains
* the Utf8Const representation of the identifier. */
tree utf8_ref;
};
/* Macros for access to language-specific slots in an identifier. */
/* UNless specifide, each of these slots contains a DECL node or null. */
/* This represents the value which the identifier has in the
file-scope namespace. */
#define IDENTIFIER_GLOBAL_VALUE(NODE) \
(((struct lang_identifier *)(NODE))->global_value)
/* This represents the value which the identifier has in the current
scope. */
#define IDENTIFIER_LOCAL_VALUE(NODE) \
(((struct lang_identifier *)(NODE))->local_value)
/* Given an identifier NODE, get the corresponding (non-handle) class.
For get_identifier ("java.lang.Number"), the result is
the struct whose DECL_ASSEMBLER_NAME is "Classjava_lang_Number". */
#define IDENTIFIER_CLASS_VALUE(NODE) IDENTIFIER_GLOBAL_VALUE(NODE)
/* Given an identifier NODE, get the corresponding handle class.
For get_identifier ("java.lang.Number"), the result is
the struct whose DECL_ASSEMBLER_NAME is "Hjava_lang_Number". */
#define IDENTIFIER_HANDLECLASS_VALUE(NODE) ???
/* Given a signature of a reference (or array) type, or a method, return the
corresponding type (if one has been allocated).
Do not use for primitive types, since they may be ambiguous.
(E.g. is "I" a signature or a class name?) */
#define IDENTIFIER_SIGNATURE_TYPE(NODE) IDENTIFIER_GLOBAL_VALUE(NODE)
/* If non-NULL: An ADDR_REF to a VAR_DECL that contains
the Utf8Const representation of the identifier. */
#define IDENTIFIER_UTF8_REF(NODE) \
(((struct lang_identifier *)(NODE))->utf8_ref)
#define IDENTIFIER_UTF8_DECL(NODE) \
TREE_OPERAND((((struct lang_identifier *)(NODE))->utf8_ref), 0)
/* For a FUNCTION_DECL, if we are compiling a .class file, then this is
the position in the .class file of the method code.
Specifically, this is the code itself, not the code attribute. */
#define DECL_CODE_OFFSET(DECL) (DECL_LANG_SPECIFIC(DECL)->code_offset)
/* Similarly, the length of the bytecode. */
#define DECL_CODE_LENGTH(DECL) (DECL_LANG_SPECIFIC(DECL)->code_length)
/* Similarly, the position of the LineNumberTable attribute. */
#define DECL_LINENUMBERS_OFFSET(DECL) \
(DECL_LANG_SPECIFIC(DECL)->linenumbers_offset)
/* Similarly, the position of the LocalVariableTable attribute
(following the standard attribute header). */
#define DECL_LOCALVARIABLES_OFFSET(DECL) \
(DECL_LANG_SPECIFIC(DECL)->localvariables_offset)
#define DECL_MAX_LOCALS(DECL) (DECL_LANG_SPECIFIC(DECL)->max_locals)
#define DECL_MAX_STACK(DECL) (DECL_LANG_SPECIFIC(DECL)->max_stack)
/* Number of local variable slots needed for the arguments of this function. */
#define DECL_ARG_SLOT_COUNT(DECL) (DECL_LANG_SPECIFIC(DECL)->arg_slot_count)
/* Pointer to the function's COMPOUND_EXPR tree */
#define DECL_FUNCTION_BODY(DECL) (DECL_LANG_SPECIFIC(DECL)->function_decl_body)
/* In a LABEL_DECL, a TREE_VEC that saves the type_map at that point. */
#define LABEL_TYPE_STATE(NODE) (DECL_INITIAL (NODE))
/* In the label of a subroutine, a dummy label that records the
state following a merge of all the ret instructions in this subroutine. */
#define LABEL_RETURN_LABEL(DECL) DECL_ARGUMENTS(DECL)
/* In the label of a sub-routine, records the type state at return.
* A local may be TYPE_UNUSED, which means that the local is not
* used (stored to or loaded from) in this subroutine - at least for
* code that we have verified so far. */
#define LABEL_RETURN_TYPE_STATE(NODE) LABEL_TYPE_STATE (LABEL_RETURN_LABEL (NODE))
/* In a TREE_VEC for a LABEL_RETURN_TYPE_STATE, notes that
TREE_VEC_LENGTH has been adjust to the correct stack size. */
#define RETURN_MAP_ADJUSTED(NODE) TREE_LANG_FLAG_2(NODE)
/* In the label of a sub-routine, a chain of the return location labels. */
#define LABEL_RETURN_LABELS(node) DECL_RESULT (LABEL_RETURN_LABEL(node))
/* In a LABEL_DECL, the next pending label.
See pending_blocks in expr.c. */
#define LABEL_PENDING_CHAIN(NODE) DECL_RESULT(NODE)
/* In a LABEL_DECL, the corresponding bytecode program counter. */
#define LABEL_PC(NODE) ((NODE)->decl.saved_insns.i)
/* Used during verification to mark the label has "changed". (See JVM Spec). */
#define LABEL_CHANGED(NODE) DECL_LANG_FLAG_6(NODE)
/* In a LABEL_DECL, true if we have verified instructions starting here. */
#define LABEL_VERIFIED(NODE) (instruction_bits[LABEL_PC(NODE)]&BCODE_VERIFIED)
/* True if this code is within a subroutine (target of a jsr). */
#define LABEL_IN_SUBR(NODE) DECL_LANG_FLAG_4(NODE)
/* True if this code is the start of a subroutine (target of a jsr). */
#define LABEL_IS_SUBR_START(NODE) DECL_LANG_FLAG_5(NODE)
/* In a LABEL_DECL, if LABEL_IN_SUBR(NODE), points to start of subroutine. */
#define LABEL_SUBR_START(NODE) DECL_ABSTRACT_ORIGIN(NODE)
/* In a LABEL_DECL that has LABEL_IS_SUBR_START, this points to the start
of surrounding subroutine in the case of a nested subroutine,
and NULL_TREE otherwise. */
#define LABEL_SUBR_CONTEXT(NODE) DECL_CONTEXT (LABEL_RETURN_LABEL (NODE))
/* The slot number for this local variable. */
#define DECL_LOCAL_SLOT_NUMBER(NODE) \
(((struct lang_decl_var*)DECL_LANG_SPECIFIC(NODE))->slot_number)
/* The start (bytecode) pc for the valid range of this local variable. */
#define DECL_LOCAL_START_PC(NODE) \
(((struct lang_decl_var*)DECL_LANG_SPECIFIC(NODE))->start_pc)
/* The end (bytecode) pc for the valid range of this local variable. */
#define DECL_LOCAL_END_PC(NODE) \
(((struct lang_decl_var*)DECL_LANG_SPECIFIC(NODE))->end_pc)
/* For a VAR_DECLor PARM_DECL, used to chain decls with the same
slot_number in decl_map. */
#define DECL_LOCAL_SLOT_CHAIN(NODE) \
(((struct lang_decl_var*)DECL_LANG_SPECIFIC(NODE))->slot_chain)
/* DECL_LANG_SPECIFIC for FUNCTION_DECLs. */
struct lang_decl
{
/* tree chain; not yet used. */
long code_offset;
int code_length;
long linenumbers_offset;
long localvariables_offset;
int arg_slots;
int max_locals, max_stack, arg_slot_count;
tree function_decl_body; /* Hold all function's statements */
};
/* DECL_LANG_SPECIFIC for VAR_DECL and PARM_DECL. */
struct lang_decl_var
{
int slot_number;
int start_pc;
int end_pc;
tree slot_chain;
};
struct lang_type
{
tree signature;
struct JCF *jcf;
};
#ifdef JAVA_USE_HANDLES
/* TYPE_BINFO_HANDLE points from a handle-class to its corresponding
non-handle-class, and vice verse. */
#define BINFO_HANDLE(NODE) TREE_VEC_ELT ((NODE), 6)
/* Given a RECORD_TYPE for a handle type, return the corresponding class. */
#define HANDLE_TO_CLASS_TYPE(HTYPE) BINFO_HANDLE (TYPE_BINFO (HTYPE))
/* Given a RECORD_TYPE for a class, return the corresponding handle type. */
#define CLASS_TO_HANDLE_TYPE(TYPE) BINFO_HANDLE (TYPE_BINFO (TYPE))
#else
#define HANDLE_TO_CLASS_TYPE(HTYPE) (HTYPE)
#define CLASS_TO_HANDLE_TYPE(TYPE) (TYPE)
#endif
#define JCF_u4 unsigned long
#define JCF_u2 unsigned short
extern tree lookup_class PROTO ((tree));
extern tree lookup_java_constructor PROTO ((tree, tree));
extern tree lookup_java_method PROTO ((tree, tree, tree));
extern tree lookup_argument_method PROTO ((tree, tree, tree));
extern tree promote_type PROTO ((tree));
extern tree get_constant PROTO ((struct JCF*, int));
extern tree get_name_constant PROTO ((struct JCF*, int));
extern tree get_class_constant PROTO ((struct JCF*, int));
extern tree parse_signature PROTO ((struct JCF *jcf, int sig_index));
extern int jcf_parse PROTO ((struct JCF*));
extern tree add_field PROTO ((tree, tree, tree, int));
extern tree add_method PROTO ((tree, int, tree, tree));
extern tree add_method_1 PROTO ((tree, int, tree, tree));
extern tree make_class ();
extern tree push_class PROTO ((tree, tree));
extern tree unmangle_classname PROTO ((const char *name, int name_length));
extern tree parse_signature_string PROTO ((const unsigned char *, int));
extern tree get_type_from_signature PROTO ((tree));
extern void layout_class PROTO ((tree));
extern tree make_class ();
extern tree build_class_ref PROTO ((tree));
extern tree build_dtable_decl PROTO ((tree));
extern tree build_internal_class_name PROTO ((tree));
extern tree build_constants_constructor ();
extern tree build_ref_from_constant_pool PROTO ((int));
extern tree build_utf8_ref PROTO ((tree));
extern tree ident_subst PROTO ((const char*, int,
const char*, int, int, const char*));
extern tree identifier_subst PROTO ((const tree,
const char *, int, int, const char *));
extern tree build_java_signature PROTO ((tree));
extern tree build_java_argument_signature PROTO ((tree));
extern void set_java_signature PROTO ((tree, tree));
extern tree build_static_field_ref PROTO ((tree));
extern tree build_address_of PROTO ((tree));
extern tree find_local_variable PROTO ((int index, tree type, int pc));
extern tree find_stack_slot PROTO ((int index, tree type));
extern tree build_prim_array_type PROTO ((tree, HOST_WIDE_INT));
extern tree build_java_array_type PROTO ((tree, HOST_WIDE_INT));
extern int is_compiled_class PROTO ((tree));
extern tree mangled_classname PROTO ((char*, tree));
extern tree lookup_label PROTO ((int));
extern tree pop_type PROTO ((tree));
extern void pop_argument_types PROTO ((tree));
extern tree decode_newarray_type PROTO ((int));
extern tree lookup_field PROTO ((tree*, tree));
extern int is_array_type_p PROTO ((tree));
extern HOST_WIDE_INT java_array_type_length PROTO ((tree));
extern void load_class PROTO ((tree, int));
extern tree lookup_name PROTO ((tree));
extern tree build_known_method_ref PROTO ((tree, tree, tree, tree, tree));
extern tree build_class_init PROTO ((tree, tree));
extern tree build_invokevirtual PROTO ((tree, tree));
extern tree invoke_build_dtable PROTO ((int, tree));
extern tree match_java_method PROTO ((tree, tree, tree));
extern tree build_field_ref PROTO ((tree, tree, tree));
extern void pushdecl_force_head PROTO ((tree));
extern tree build_java_binop PROTO ((enum tree_code, tree, tree, tree));
extern tree binary_numeric_promotion PROTO ((tree, tree, tree *, tree *));
extern tree build_decl_no_layout PROTO ((enum tree_code, tree, tree));
extern tree build_java_arrayaccess PROTO ((tree, tree, tree));
extern tree build_newarray PROTO ((int, tree));
extern tree build_anewarray PROTO ((tree, tree));
extern tree build_java_array_length_access PROTO ((tree));
extern tree build_java_arraynull_check PROTO ((tree, tree, tree));
extern tree create_label_decl PROTO ((tree));
extern void push_labeled_block PROTO ((tree));
/* Access flags etc for a method (a FUNCTION_DECL): */
#define METHOD_PUBLIC(DECL) DECL_LANG_FLAG_1 (DECL)
#define METHOD_PRIVATE(DECL) TREE_PRIVATE (DECL)
#define METHOD_PROTECTED(DECL) TREE_PROTECTED (DECL)
#define METHOD_STATIC(DECL) DECL_LANG_FLAG_2 (DECL)
#define METHOD_FINAL(DECL) DECL_LANG_FLAG_3 (DECL)
#define METHOD_SYNCHRONIZED(DECL) DECL_LANG_FLAG_4 (DECL)
#define METHOD_NATIVE(DECL) DECL_EXTERNAL(DECL)
#define METHOD_ABSTRACT(DECL) DECL_LANG_FLAG_5 (DECL)
#define METHOD_TRANSIENT(DECL) DECL_LANG_FLAG_6 (DECL)
#define DECL_CONSTRUCTOR_P(DECL) DECL_LANG_FLAG_7(DECL)
/* Access flags etc for a variable/field (a FIELD_DECL): */
#define FIELD_PRIVATE(DECL) TREE_PRIVATE (DECL)
#define FIELD_PROTECTED(DECL) TREE_PROTECTED (DECL)
#define FIELD_PUBLIC(DECL) DECL_LANG_FLAG_1 (DECL)
#define FIELD_STATIC(DECL) TREE_STATIC (DECL)
#define FIELD_FINAL(DECL) DECL_LANG_FLAG_3 (DECL)
#define FIELD_VOLATILE(DECL) DECL_LANG_FLAG_4 (DECL)
#define FIELD_TRANSIENT(DECL) DECL_LANG_FLAG_5 (DECL)
/* Initialized flag on variable/field/parm decl */
#define INITIALIZED_P(DECL) DECL_LANG_FLAG_6 (DECL)
/* Access flags etc for a class (a TYPE_DECL): */
#define CLASS_PUBLIC(DECL) DECL_LANG_FLAG_1 (DECL)
#define CLASS_FINAL(DECL) DECL_LANG_FLAG_3 (DECL)
#define CLASS_INTERFACE(DECL) DECL_LANG_FLAG_4 (DECL)
#define CLASS_ABSTRACT(DECL) DECL_LANG_FLAG_5 (DECL)
#define CLASS_SUPER(DECL) DECL_LANG_FLAG_6 (DECL)
/* The number of virtual methods in this class's dispatch table.
Does not include initial two dummy entries (one points to the
Class object, and the other is for G++ -fvtable-thunks compatibility). */
#define TYPE_NVIRTUALS(TYPE) TYPE_BINFO_VIRTUALS (TYPE)
/* A TREE_VEC (indexed by DECL_VINDEX) containing this class's
virtual methods. */
#define TYPE_VTABLE(TYPE) TYPE_BINFO_VTABLE(TYPE)
/* True of a RECORD_TYPE of a class/interface type (not array type) */
#define CLASS_P(TYPE) TYPE_LANG_FLAG_4 (TYPE)
/* Use CLASS_LOADED_P? FIXME */
#define CLASS_COMPLETE_P(DECL) DECL_LANG_FLAG_2 (DECL)
/* This maps a bytecode offset (PC) to various flags,
listed below (starting with BCODE_). */
extern char *instruction_bits;
/* True iff the byte is the start of an instruction. */
#define BCODE_INSTRUCTION_START 1
/* True iff there is a jump to this location. */
#define BCODE_JUMP_TARGET 2
/* True iff there is a return to this location.
(I.e. the preceedng instruction was a call.) */
#define BCODE_RETURN_TARGET 4
/* True iff this is the start of an exception handler. */
#define BCODE_EXCEPTION_TARGET 16
/* True iff there is a jump to this location (and it needs a label). */
#define BCODE_TARGET \
(BCODE_JUMP_TARGET|BCODE_RETURN_TARGET \
| BCODE_EXCEPTION_TARGET)
/* True iff there is an entry in the linenumber table for this location. */
#define BCODE_HAS_LINENUMBER 32
/* True iff there is more than one entry in the linenumber table for
this location. (This probably does not make much sense.) */
#define BCODE_HAS_MULTI_LINENUMBERS 64
/* True if this instruction has been verified. */
#define BCODE_VERIFIED 8
/* A pointer to the line number table of the current method. */
extern unsigned char *linenumber_table;
/* The length (in items) of the line number table. */
extern int linenumber_count;
/* In type_map, means that slot is uninitialized or otherwise unusable. */
#define TYPE_UNKNOWN NULL_TREE
/* In type_map, means the second half of a 64-bit double or long. */
#define TYPE_SECOND void_type_node
/* In type_map, means the null type (i.e. type of a null reference). */
#define TYPE_NULL ptr_type_node
/* In a type map means the type the address subroutine return address. */
#define TYPE_RETURN_ADDR return_address_type_node
/* In a subroutine's return type map, indicates that the slot was neither
used nor set in the subroutine. */
#define TYPE_UNUSED error_mark_node
/* A array mapping variable/stack slot index to the type current
in that variable/stack slot.
TYPE_UNKNOWN, TYPE_SECOND, and TYPE_NULL are special cases. */
extern tree *type_map;
/* Map a stack index to the type currently in that slot. */
#define stack_type_map (type_map+DECL_MAX_LOCALS(current_function_decl))
/* True iff TYPE takes two variable/stack slots. */
#define TYPE_IS_WIDE(TYPE) \
((TYPE) == double_type_node || (TYPE) == long_type_node)
/* True iff TYPE is a Java array type. */
#define TYPE_ARRAY_P(TYPE) TYPE_LANG_FLAG_1 (TYPE)
/* If FUNCTION_TYPE or METHOD_TYPE: cache for build_java_argument_signature. */
#define TYPE_ARGUMENT_SIGNATURE(TYPE) TYPE_VFIELD(TYPE)
/* Given an array type, give the type of the elements. */
/* FIXME this use of TREE_TYPE conflicts with something or other. */
#define TYPE_ARRAY_ELEMENT(ATYPE) TREE_TYPE(ATYPE)
/* True if class TYPE has been loaded. */
#define CLASS_LOADED_P(TYPE) TYPE_LANG_FLAG_2 (TYPE)
/* True if class TYPE was defined in Java source code. */
#define CLASS_FROM_SOURCE_P(TYPE) TYPE_LANG_FLAG_3 (TYPE)
/* True if identifier ID was seen while processing a single type import stmt */
#define IS_A_SINGLE_IMPORT_CLASSFILE_NAME_P(ID) TREE_LANG_FLAG_0 (ID)
/* True if identifier ID was seen while processing an import statement */
#define IS_A_CLASSFILE_NAME(ID) TREE_LANG_FLAG_1 (ID)
/* True if ID is a qualified named (contains . or /) */
#define QUALIFIED_P(ID) TREE_LANG_FLAG_2 (ID)
/* True if ID is an already processed import on demand */
#define IS_AN_IMPORT_ON_DEMAND_P(ID) TREE_LANG_FLAG_3 (ID)
/* True if EXPR is RHS sub-tree of a compound assign expression */
#define COMPOUND_ASSIGN_P(EXPR) TREE_LANG_FLAG_1 (EXPR)
/* True if EXPR (a WFL in that case) was created after the
reduction of PRIMARY . XXX */
#define PRIMARY_P(EXPR) TREE_LANG_FLAG_2 (EXPR)
/* True if EXPR (a MODIFY_EXPR in that case) is the result of variable
initialization during its declaration */
#define MODIFY_EXPR_FROM_INITIALIZATION_P(EXPR) TREE_LANG_FLAG_2 (EXPR)
/* True if EXPR (a WFL in that case) resolves into an expression name */
#define RESOLVE_EXPRESSION_NAME_P(WFL) TREE_LANG_FLAG_0 (WFL)
/* True if EXPR (a LOOP_EXPR in that case) is part of a for statement */
#define IS_FOR_LOOP_P(EXPR) TREE_LANG_FLAG_0 (EXPR)
/* True if EXPR (a WFL in that case) resolves into a package name */
#define RESOLVE_PACKAGE_NAME_P(WFL) TREE_LANG_FLAG_3 (WFL)
/* True if EXPR (a WFL in that case) resolves into a type name */
#define RESOLVE_TYPE_NAME_P(WFL) TREE_LANG_FLAG_4 (WFL)
/* True if STMT (a WFL in that case) holds a BREAK statement */
#define IS_BREAK_STMT_P(WFL) TREE_LANG_FLAG_5 (WFL)
/* Add a FIELD_DECL to RECORD_TYPE RTYPE.
The field has name NAME (a char*), and type FTYPE.
Unless this is the first field, FIELD most hold the previous field.
FIELD is set to the newly created FIELD_DECL.
We set DECL_ARTIFICIAL so these fields get skipped by make_class_data
if compiling java.lang.Object or java.lang.Class. */
#define PUSH_FIELD(RTYPE, FIELD, NAME, FTYPE) \
{ tree tmp_field = build_decl (FIELD_DECL, get_identifier(NAME), FTYPE); \
if (TYPE_FIELDS (RTYPE) == NULL_TREE) TYPE_FIELDS (RTYPE) = tmp_field; \
else TREE_CHAIN(FIELD) = tmp_field; \
DECL_CONTEXT (tmp_field) = RTYPE; \
DECL_ARTIFICIAL (tmp_field) = 1; \
FIELD = tmp_field; }
#define FINISH_RECORD(RTYPE) layout_type (RTYPE)
/* Start building a RECORD_TYPE constructor with a given TYPE in CONS. */
#define START_RECORD_CONSTRUCTOR(CONS, CTYPE) { \
CONS = build (CONSTRUCTOR, CTYPE, NULL_TREE, NULL_TREE);\
TREE_CHAIN(CONS) = TYPE_FIELDS (CTYPE); }
/* Append a field initializer to CONS for the dummy field for the inherited
fields. The dummy field has the given VALUE, and the same type as the
super-class. Must be specified before calls to PUSH_FIELD_VALUE. */
#define PUSH_SUPER_VALUE(CONS, VALUE) {\
tree field = TREE_CHAIN(CONS);\
if (DECL_NAME (field) != NULL_TREE) abort();\
CONSTRUCTOR_ELTS(CONS) = tree_cons (field, VALUE, CONSTRUCTOR_ELTS(CONS));\
TREE_CHAIN(CONS) = TREE_CHAIN (field); }
/* Append a field initializer to CONS for a field with the given VALUE.
NAME is a char* string used for error checking;
the initializer must be specified in order. */
#define PUSH_FIELD_VALUE(CONS, NAME, VALUE) {\
tree field = TREE_CHAIN(CONS);\
if (strcmp (IDENTIFIER_POINTER (DECL_NAME (field)), NAME) != 0) abort();\
CONSTRUCTOR_ELTS(CONS) = tree_cons (field, VALUE, CONSTRUCTOR_ELTS(CONS));\
TREE_CHAIN(CONS) = TREE_CHAIN (field); }
/* Finish creating a record CONSTRUCTOR CONS. */
#define FINISH_RECORD_CONSTRUCTOR(CONS) \
CONSTRUCTOR_ELTS(CONS) = nreverse (CONSTRUCTOR_ELTS(CONS))
/* New tree code for expression, so we can expand then individually. */
#define JAVA_UNARY_PLUS_EXPR ((int)LAST_AND_UNUSED_TREE_CODE + 2)
#define JAVA_NEW_ARRAY_EXPR ((int)LAST_AND_UNUSED_TREE_CODE + 3)
#define JAVA_NEW_CLASS_EXPR ((int)LAST_AND_UNUSED_TREE_CODE + 4)
#define JAVA_THIS_EXPR ((int)LAST_AND_UNUSED_TREE_CODE + 5)
/* Macro(s) using the definitions above */
#define CALL_CONSTRUCTOR_P(NODE) (TREE_CODE (NODE) == JAVA_NEW_CLASS_EXPR)

314
gcc/java/javaop.def Normal file
View file

@ -0,0 +1,314 @@
/* Table of opcodes for byte codes defined by the Java(TM) virtual
machine specification.
Copyright (C) 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC 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.
GNU CC 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, 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.
Written by Per Bothner <bothner@cygnus.com>, February 1996.
*/
/* JAVAOP (OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE), where:
OPNAME is the name of the opcode.
OPCODE is the 1-byte opcode value.
OPKIND is the kind of operation.
OPERAND_TYPE is the type operands affected.
OPERAND_VALUE tells where to get the value. (Its meaning
depends on OPKIND.) */
/* Various macro used in OPERAND_VALUE:
IMMEDIATE_s1: An immediate signed 1-byte value in the byte-code stream.
IMMEDIATE_s2: An immediate signed 2-byte value in the byte-code stream.
IMMEDIATE_u1: An immediate unsigned 1-byte value in the byte-code stream.
IMMEDIATE_u2: An immediate unsigned 2-byte value in the byte-code stream.
CONST_INDEX_1: An immediate unsigned 1-byte index into the constant pool.
CONST_INDEX_2: An immediate unsigned 2-byte index into the constant pool.
*/
/* More specifically, this is the meaning of the various OPKINDs:
BINOP: binary operation
OPERAND_TYPE is the argument type.
OPERAND_VALUE is PLUS, MINUS, MULT, TRUNC_DIV, RDIV, REM,
LSHIFT, RSHIFT, URSHIFT, BIT_AND, BIT_IOR, BIT_XOR,
COMPARE, COMPARE_L, or COMPARE_G.
UNOP: unary operation
OPERAND_TYPE is the argument type.
OPERAND_VALUE is NEG.
INVOKE: invoke operations
OPERAND_TYPE is VIRTUAL, SPECIAL, STATIC, or INTERFACE.
OPERAND_VALUE is 1 if interface, 0 otherwise.
OBJECT: new, checkcast, instanceof
OPERAND_TYPE is PTR.
OPERAND_VALUE is NEW, CHECKCAST, or INSTANCEOF.
BRANCH: branch operations
OPERAND_TYPE is GOTO, CALL, or RETURN.
OPERAND_VALUE is IMMEDIATE_s2, VAR_INDEX_1, IMMEDIATE_s4,
or VAR_INDEX_2.
STACK: Various stack operations.
PUSHC: Push a constant onto the operand stack.
OPERAND_VALUE maybe be the value to push,
or IMMEDIATE_s1 or IMMEDIATE_s2 if the constant is immediate,
or CONST_INDEX_1 or CONST_INDEX_2 for a constant pool index.
LOAD: Push a value from a local variable onto the operand stack.
OPERAND_VALUE is the index of the local variable in the current
Java frame. It can be a literal, or IMMEDIATE_i2.
CONVERT: Convert top of stack value from one type to another.
OPERAND_TYPE is the argument type.
OPERAND_VALUE is the result type.
TEST: Compares an integer (popped from the stack) against zero.
If the test (in OPERAND_VALUE) is true, goto a relative
offset given by the next two bytes.
COND: Compares two values (popped from the stack) againt each other.
If the test (in OPERAND_VALUE) is true, goto a relative
offset given by the next two bytes.
SWITCH:
OPERAND_VALUE is either TABLE or LOOKUP.
ARRAY:
OPERAND_VALUE is LOAD, STORE, LENGTH, or NEW.
FIELD: Extracts from or stores into a field.
OPERAND_TYPE is 1 for a static field, 0 for a regular field.
OPERAND_VALUE is 1 for a put operation, 0 for a get operation.
SPECIAL:
Random bunch of opcodes.
*/
JAVAOP (nop, 0, STACK, POP, 0)
JAVAOP (aconst_null, 1, PUSHC, PTR, 0)
JAVAOP (iconst_m1, 2, PUSHC, INT, -1)
JAVAOP (iconst_0, 3, PUSHC, INT, 0)
JAVAOP (iconst_1, 4, PUSHC, INT, 1)
JAVAOP (iconst_2, 5, PUSHC, INT, 2)
JAVAOP (iconst_3, 6, PUSHC, INT, 3)
JAVAOP (iconst_4, 7, PUSHC, INT, 4)
JAVAOP (iconst_5, 8, PUSHC, INT, 5)
JAVAOP (lconst_0, 9, PUSHC, LONG, 0)
JAVAOP (lconst_1, 10, PUSHC, LONG, 1)
JAVAOP (fconst_0, 11, PUSHC, FLOAT, 0)
JAVAOP (fconst_1, 12, PUSHC, FLOAT, 1)
JAVAOP (fconst_2, 13, PUSHC, FLOAT, 2)
JAVAOP (dconst_0, 14, PUSHC, DOUBLE, 0)
JAVAOP (dconst_1, 15, PUSHC, DOUBLE, 1)
JAVAOP (bipush, 16, PUSHC, INT, IMMEDIATE_s1)
JAVAOP (sipush, 17, PUSHC, INT, IMMEDIATE_s2)
JAVAOP (ldc, 18, PUSHC, INT, CONST_INDEX_1)
JAVAOP (ldc_w, 19, PUSHC, INT, CONST_INDEX_2)
JAVAOP (ldc2_w, 20, PUSHC, LONG, CONST_INDEX_2)
JAVAOP (iload, 21, LOAD, INT, IMMEDIATE_u1)
JAVAOP (lload, 22, LOAD, LONG, IMMEDIATE_u1)
JAVAOP (fload, 23, LOAD, FLOAT, IMMEDIATE_u1)
JAVAOP (dload, 24, LOAD, DOUBLE, IMMEDIATE_u1)
JAVAOP (aload, 25, LOAD, PTR, IMMEDIATE_u1)
JAVAOP (iload_0, 26, LOAD, INT, 0)
JAVAOP (iload_1, 27, LOAD, INT, 1)
JAVAOP (iload_2, 28, LOAD, INT, 2)
JAVAOP (iload_3, 29, LOAD, INT, 3)
JAVAOP (lload_0, 30, LOAD, LONG, 0)
JAVAOP (lload_1, 31, LOAD, LONG, 1)
JAVAOP (lload_2, 32, LOAD, LONG, 2)
JAVAOP (lload_3, 33, LOAD, LONG, 3)
JAVAOP (fload_0, 34, LOAD, FLOAT, 0)
JAVAOP (fload_1, 35, LOAD, FLOAT, 1)
JAVAOP (fload_2, 36, LOAD, FLOAT, 2)
JAVAOP (fload_3, 37, LOAD, FLOAT, 3)
JAVAOP (dload_0, 38, LOAD, DOUBLE, 0)
JAVAOP (dload_1, 39, LOAD, DOUBLE, 1)
JAVAOP (dload_2, 40, LOAD, DOUBLE, 2)
JAVAOP (dload_3, 41, LOAD, DOUBLE, 3)
JAVAOP (aload_0, 42, LOAD, PTR, 0)
JAVAOP (aload_1, 43, LOAD, PTR, 1)
JAVAOP (aload_2, 44, LOAD, PTR, 2)
JAVAOP (aload_3, 45, LOAD, PTR, 3)
JAVAOP (iaload, 46, ARRAY, INT, LOAD)
JAVAOP (laload, 47, ARRAY, LONG, LOAD)
JAVAOP (faload, 48, ARRAY, FLOAT, LOAD)
JAVAOP (daload, 49, ARRAY, DOUBLE, LOAD)
JAVAOP (aaload, 50, ARRAY, PTR, LOAD)
JAVAOP (baload, 51, ARRAY, BYTE, LOAD)
JAVAOP (caload, 52, ARRAY, CHAR, LOAD)
JAVAOP (saload, 53, ARRAY, SHORT, LOAD)
JAVAOP (istore, 54, STORE, INT, IMMEDIATE_u1)
JAVAOP (lstore, 55, STORE, LONG, IMMEDIATE_u1)
JAVAOP (fstore, 56, STORE, FLOAT, IMMEDIATE_u1)
JAVAOP (dstore, 57, STORE, DOUBLE, IMMEDIATE_u1)
JAVAOP (astore, 58, STORE, PTR, IMMEDIATE_u1)
JAVAOP (istore_0, 59, STORE, INT, 0)
JAVAOP (istore_1, 60, STORE, INT, 1)
JAVAOP (istore_2, 61, STORE, INT, 2)
JAVAOP (istore_3, 62, STORE, INT, 3)
JAVAOP (lstore_0, 63, STORE, LONG, 0)
JAVAOP (lstore_1, 64, STORE, LONG, 1)
JAVAOP (lstore_2, 65, STORE, LONG, 2)
JAVAOP (lstore_3, 66, STORE, LONG, 3)
JAVAOP (fstore_0, 67, STORE, FLOAT, 0)
JAVAOP (fstore_1, 68, STORE, FLOAT, 1)
JAVAOP (fstore_2, 69, STORE, FLOAT, 2)
JAVAOP (fstore_3, 70, STORE, FLOAT, 3)
JAVAOP (dstore_0, 71, STORE, DOUBLE, 0)
JAVAOP (dstore_1, 72, STORE, DOUBLE, 1)
JAVAOP (dstore_2, 73, STORE, DOUBLE, 2)
JAVAOP (dstore_3, 74, STORE, DOUBLE, 3)
JAVAOP (astore_0, 75, STORE, PTR, 0)
JAVAOP (astore_1, 76, STORE, PTR, 1)
JAVAOP (astore_2, 77, STORE, PTR, 2)
JAVAOP (astore_3, 78, STORE, PTR, 3)
JAVAOP (iastore, 79, ARRAY, INT, STORE)
JAVAOP (lastore, 80, ARRAY, LONG, STORE)
JAVAOP (fastore, 81, ARRAY, FLOAT, STORE)
JAVAOP (dastore, 82, ARRAY, DOUBLE, STORE)
JAVAOP (aastore, 83, ARRAY, PTR, STORE)
JAVAOP (bastore, 84, ARRAY, BYTE, STORE)
JAVAOP (castore, 85, ARRAY, CHAR, STORE)
JAVAOP (sastore, 86, ARRAY, SHORT, STORE)
JAVAOP (pop, 87, STACK, POP, 1)
JAVAOP (pop2, 88, STACK, POP, 2)
JAVAOP (dup, 89, STACK, DUP, 1)
JAVAOP (dup_x1, 90, STACK, DUPx1, 1)
JAVAOP (dup_x2, 91, STACK, DUPx2, 1)
JAVAOP (dup2, 92, STACK, DUP, 2)
JAVAOP (dup2_x1, 93, STACK, DUPx1, 2)
JAVAOP (dup2_x2, 94, STACK, DUPx2, 2)
JAVAOP (swap, 95, STACK, SWAP, 0)
JAVAOP (iadd, 96, BINOP, INT, PLUS)
JAVAOP (ladd, 97, BINOP, LONG, PLUS)
JAVAOP (fadd, 98, BINOP, FLOAT, PLUS)
JAVAOP (dadd, 99, BINOP, DOUBLE, PLUS)
JAVAOP (isub, 100, BINOP, INT, MINUS)
JAVAOP (lsub, 101, BINOP, LONG, MINUS)
JAVAOP (fsub, 102, BINOP, FLOAT, MINUS)
JAVAOP (dsub, 103, BINOP, DOUBLE, MINUS)
JAVAOP (imul, 104, BINOP, INT, MULT)
JAVAOP (lmul, 105, BINOP, LONG, MULT)
JAVAOP (fmul, 106, BINOP, FLOAT, MULT)
JAVAOP (dmul, 107, BINOP, DOUBLE, MULT)
JAVAOP (idiv, 108, BINOP, INT, TRUNC_DIV)
JAVAOP (ldiv, 109, BINOP, LONG, TRUNC_DIV)
JAVAOP (fdiv, 110, BINOP, FLOAT, RDIV)
JAVAOP (ddiv, 111, BINOP, DOUBLE, RDIV)
JAVAOP (irem, 112, BINOP, INT, REM)
JAVAOP (lrem, 113, BINOP, LONG, REM)
JAVAOP (frem, 114, BINOP, FLOAT, REM)
JAVAOP (drem, 115, BINOP, DOUBLE, REM)
JAVAOP (ineg, 116, UNOP, INT, NEG)
JAVAOP (lneg, 117, UNOP, LONG, NEG)
JAVAOP (fneg, 118, UNOP, FLOAT, NEG)
JAVAOP (dneg, 119, UNOP, DOUBLE, NEG)
JAVAOP (ishl, 120, BINOP, INT, LSHIFT)
JAVAOP (lshl, 121, BINOP, LONG, LSHIFT)
JAVAOP (ishr, 122, BINOP, INT, RSHIFT)
JAVAOP (lshr, 123, BINOP, LONG, RSHIFT)
JAVAOP (iushr, 124, BINOP, INT, URSHIFT)
JAVAOP (lushr, 125, BINOP, LONG, URSHIFT)
JAVAOP (iand, 126, BINOP, INT, BIT_AND)
JAVAOP (land, 127, BINOP, LONG, BIT_AND)
JAVAOP (ior, 128, BINOP, INT, BIT_IOR)
JAVAOP (lor, 129, BINOP, LONG, BIT_IOR)
JAVAOP (ixor, 130, BINOP, INT, BIT_XOR)
JAVAOP (lxor, 131, BINOP, LONG, BIT_XOR)
JAVAOP (iinc, 132, SPECIAL, INT, IINC)
JAVAOP (i2l, 133, CONVERT, INT, LONG)
JAVAOP (i2f, 134, CONVERT, INT, FLOAT)
JAVAOP (i2d, 135, CONVERT, INT, DOUBLE)
JAVAOP (l2i, 136, CONVERT, LONG, INT)
JAVAOP (l2f, 137, CONVERT, LONG, FLOAT)
JAVAOP (l2d, 138, CONVERT, LONG, DOUBLE)
JAVAOP (f2i, 139, CONVERT, FLOAT, INT)
JAVAOP (f2l, 140, CONVERT, FLOAT, LONG)
JAVAOP (f2d, 141, CONVERT, FLOAT, DOUBLE)
JAVAOP (d2i, 142, CONVERT, DOUBLE, INT)
JAVAOP (d2l, 143, CONVERT, DOUBLE, LONG)
JAVAOP (d2f, 144, CONVERT, DOUBLE, FLOAT)
JAVAOP (i2b, 145, CONVERT2, INT, BYTE)
JAVAOP (i2c, 146, CONVERT2, INT, CHAR)
JAVAOP (i2s, 147, CONVERT2, INT, SHORT)
JAVAOP (lcmp, 148, BINOP, LONG, COMPARE)
JAVAOP (fcmpl, 149, BINOP, FLOAT, COMPARE_L)
JAVAOP (fcmpg, 150, BINOP, FLOAT, COMPARE_G)
JAVAOP (dcmpl, 151, BINOP, DOUBLE, COMPARE_L)
JAVAOP (dcmpg, 152, BINOP, DOUBLE, COMPARE_G)
JAVAOP (ifeq, 153, TEST, INT, EQ)
JAVAOP (ifne, 154, TEST, INT, NE)
JAVAOP (iflt, 155, TEST, INT, LT)
JAVAOP (ifge, 156, TEST, INT, GE)
JAVAOP (ifgt, 157, TEST, INT, GT)
JAVAOP (ifle, 158, TEST, INT, LE)
JAVAOP (if_icmpeq, 159, COND, INT, EQ)
JAVAOP (if_icmpne, 160, COND, INT, NE)
JAVAOP (if_icmplt, 161, COND, INT, LT)
JAVAOP (if_icmpge, 162, COND, INT, GE)
JAVAOP (if_icmpgt, 163, COND, INT, GT)
JAVAOP (if_icmple, 164, COND, INT, LE)
JAVAOP (if_acmpeq, 165, COND, PTR, EQ)
JAVAOP (if_acmpne, 166, COND, PTR, NE)
JAVAOP (goto, 167, BRANCH, GOTO, IMMEDIATE_s2)
JAVAOP (jsr, 168, JSR, CALL, IMMEDIATE_s2)
JAVAOP (ret, 169, RET, RETURN, VAR_INDEX_1)
JAVAOP (tableswitch, 170, SWITCH, INT, TABLE)
JAVAOP (lookupswitch, 171, SWITCH, INT, LOOKUP)
JAVAOP (ireturn, 172, RETURN, INT, 0)
JAVAOP (lreturn, 173, RETURN, LONG, 0)
JAVAOP (freturn, 174, RETURN, FLOAT, 0)
JAVAOP (dreturn, 175, RETURN, DOUBLE, 0)
JAVAOP (areturn, 176, RETURN, PTR, 0)
JAVAOP (return, 177, RETURN, VOID, 0)
JAVAOP (getstatic, 178, FIELD, 1, 0)
JAVAOP (putstatic, 179, FIELD, 1, 1)
JAVAOP (getfield, 180, FIELD, 0, 0)
JAVAOP (putfield, 181, FIELD, 0, 1)
JAVAOP (invokevirtual, 182, INVOKE, VIRTUAL,0)
JAVAOP (invokespecial, 183, INVOKE, SPECIAL, 0)
JAVAOP (invokestatic, 184, INVOKE, STATIC, 0)
JAVAOP (invokeinterface,185, INVOKE, INTERFACE, 1)
JAVAOP (new, 187, OBJECT, PTR, NEW)
JAVAOP (newarray, 188, ARRAY, NUM, NEW)
JAVAOP (anewarray, 189, ARRAY, PTR, NEW)
JAVAOP (arraylength, 190, ARRAY, INT, LENGTH)
JAVAOP (athrow, 191, SPECIAL, ANY, THROW)
JAVAOP (checkcast, 192, OBJECT, PTR, CHECKCAST)
JAVAOP (instanceof, 193, OBJECT, PTR, INSTANCEOF)
JAVAOP (monitorenter, 194, SPECIAL, MONITOR, ENTER)
JAVAOP (monitorexit, 195, SPECIAL, MONITOR, EXIT)
JAVAOP (wide, 196, SPECIAL, ANY, WIDE)
JAVAOP (multianewarray,197, ARRAY, MULTI, NEW)
JAVAOP (ifnull, 198, TEST, PTR, EQ)
JAVAOP (ifnonnull, 199, TEST, PTR, NE)
JAVAOP (goto_w, 200, BRANCH, GOTO, IMMEDIATE_s4)
JAVAOP (jsr_w, 201, JSR, CALL, IMMEDIATE_s4)
JAVAOP (breakpoint, 202, SPECIAL, ANY, BREAK)
JAVAOP (ret_w, 209, RET, RETURN, VAR_INDEX_2)
JAVAOP (impdep1, 254, IMPL, ANY, 1)
JAVAOP (impdep2, 255, IMPL, ANY, 2)

142
gcc/java/javaop.h Normal file
View file

@ -0,0 +1,142 @@
/* Utility macros to handle Java(TM) byte codes.
Copyright (C) 1996 Free Software Foundation, Inc.
This program 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.
This program 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, 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. */
/* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
#ifndef JAVAOP_H
#define JAVAOP_H
typedef char int8;
typedef unsigned char uint8;
#ifndef int16
#define int16 short
#endif
typedef unsigned int16 uint16;
#ifndef int32
#define int32 long
#endif
typedef unsigned int32 uint32;
/* A signed 64-bit (or more) integral type, suiteable for Java's 'long'. */
#ifndef int64
#define int64 long long
#endif
/* An unsigned 64-bit (or more) integral type, same length as int64. */
#ifndef uint64
#define uint64 unsigned int64
#endif
typedef uint16 jchar;
typedef int8 jbyte;
typedef int16 jshort;
typedef int32 jint;
typedef int64 jlong;
typedef void* jref;
/* A 32-bit IEEE single-precision float. */
#ifndef jfloat
#define jfloat float
#endif
/* A 32-bit IEEE double-precision float. */
#ifndef jdouble
#define jdouble double
#endif
union Word {
jint i;
jfloat f;
void *p;
};
/* A jword is an unsigned integral type big enough for a 32-bit jint
or jfloat *or* a pointer. It is the type appropriate for stack
locations and local variables in a Java interpreter. */
#ifndef jword
#define jword uint32
#endif
#if !defined(inline) && !defined(__GC__) && !defined(__cplusplus)
#define inline static
#endif
#ifndef IMMEDIATE_u1
#define IMMEDIATE_u1 (PC++, CHECK_PC_IN_RANGE(PC), BCODE[PC-1])
#endif
#ifndef IMMEDIATE_s1
#define IMMEDIATE_s1 (PC++, CHECK_PC_IN_RANGE(PC), (signed char)BCODE[PC-1])
#endif
#ifndef IMMEDIATE_s2
#define IMMEDIATE_s2 (PC+=2, CHECK_PC_IN_RANGE(PC), \
(signed char) BCODE[PC-2] * 256 + BCODE[PC-1])
#endif
#ifndef IMMEDIATE_u2
#define IMMEDIATE_u2 (PC+=2, CHECK_PC_IN_RANGE(PC),\
(BCODE[PC-2] * 256 + BCODE[PC-1]))
#endif
#ifndef IMMEDIATE_s4
#define IMMEDIATE_s4 (PC+=4, CHECK_PC_IN_RANGE(PC), \
((jint)((BCODE[PC-4] << 24) | (BCODE[PC-3] << 16) \
| (BCODE[PC-2] << 8) | (BCODE[PC-1]))))
#endif
inline jfloat
WORD_TO_FLOAT(jword w)
{ union Word wu;
wu.i = w;
return wu.f;
}
inline jlong
WORDS_TO_LONG(jword hi, jword lo)
{
return ((jlong) hi << 32) | ((jlong)lo & (((jlong)1 << 32) -1));
}
union DWord {
jdouble d;
jlong l;
jword w[2];
};
inline jdouble
WORDS_TO_DOUBLE(jword hi, jword lo)
{ union DWord wu;
wu.l = WORDS_TO_LONG(hi, lo);
return wu.d;
}
/* If PREFIX_CHAR is the first character of the Utf8 encoding of a character,
return the number of bytes taken by the encoding.
Return -1 for a continuation character. */
#define UT8_CHAR_LENGTH(PREFIX_CHAR) \
((unsigned char)(PREFIX_CHAR) < 128 ? 1 \
: ((PREFIX_CHAR) & 0x40) == 0 ? -1 \
: ((PREFIX_CHAR) & 0x20) == 0 ? 2 \
: ((PREFIX_CHAR) & 0x10) == 0 ? 3 \
: ((PREFIX_CHAR) & 0x08) == 0 ? 4 : 5)
#endif /* !JAVAOP_H */

1072
gcc/java/jcf-dump.c Normal file

File diff suppressed because it is too large Load diff

574
gcc/java/jcf-io.c Normal file
View file

@ -0,0 +1,574 @@
/* Utility routines for finding and reading Java(TM) .class files.
Copyright (C) 1996 Free Software Foundation, Inc.
This program 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.
This program 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, 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. */
/* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
#include <stdio.h>
#define ENABLE_UNZIP 1
#include "jcf.h"
#ifdef __STDC__
#include <stdlib.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
/* DOS brain-damage */
#ifndef O_BINARY
#define O_BINARY 0 /* MS-DOS brain-damage */
#endif
char *classpath;
int
DEFUN(jcf_unexpected_eof, (jcf, count),
JCF *jcf AND int count)
{
if (jcf->filename)
fprintf (stderr, "Premature end of .class file %s.\n", jcf->filename);
else
fprintf (stderr, "Premature end of .class file <stdin>.\n");
exit (-1);
}
void
DEFUN(jcf_trim_old_input, (jcf),
JCF *jcf)
{
int count = jcf->read_ptr - jcf->buffer;
if (count > 0)
{
memmove (jcf->buffer, jcf->read_ptr, jcf->read_end - jcf->read_ptr);
jcf->read_ptr -= count;
jcf->read_end -= count;
}
}
int
DEFUN(jcf_filbuf_from_stdio, (jcf, count),
JCF *jcf AND int count)
{
FILE *file = (FILE*) (jcf->read_state);
if (count > jcf->buffer_end - jcf->read_ptr)
{
JCF_u4 old_read_ptr = jcf->read_ptr - jcf->buffer;
JCF_u4 old_read_end = jcf->read_end - jcf->buffer;
JCF_u4 old_size = jcf->buffer_end - jcf->buffer;
JCF_u4 new_size = (old_size == 0 ? 2000 : 2 * old_size) + count;
unsigned char *new_buffer = jcf->buffer == NULL ? ALLOC (new_size)
: REALLOC (jcf->buffer, new_size);
jcf->buffer = new_buffer;
jcf->buffer_end = new_buffer + new_size;
jcf->read_ptr = new_buffer + old_read_ptr;
jcf->read_end = new_buffer + old_read_end;
}
count -= jcf->read_end - jcf->read_ptr;
if (count <= 0)
return 0;
if (fread (jcf->read_end, 1, count, file) != count)
jcf_unexpected_eof (jcf, count);
jcf->read_end += count;
return 0;
}
#if ENABLE_UNZIP
#include "zipfile.h"
struct ZipFileCache *SeenZipFiles = NULL;
int
DEFUN(open_in_zip, (jcf,
zipfile, zipmember),
JCF *jcf AND const char *zipfile AND const char *zipmember)
{
struct ZipFileCache* zipf;
ZipDirectory *zipd;
int i, len;
for (zipf = SeenZipFiles; ; zipf = zipf->next)
{
if (zipf == NULL)
{
char magic [4];
int fd = open (zipfile, O_RDONLY | O_BINARY);
if (read (fd, magic, 4) != 4 || GET_u4 (magic) != (JCF_u4)ZIPMAGIC)
return -1;
lseek (fd, 0L, SEEK_SET);
zipf = ALLOC (sizeof (struct ZipFileCache) + strlen (zipfile) + 1);
zipf->next = SeenZipFiles;
zipf->name = (char*)(zipf+1);
strcpy (zipf->name, zipfile);
SeenZipFiles = zipf;
zipf->z.fd = fd;
if (fd == -1)
{
/* A missing zip file is not considered an error. */
zipf->z.count = 0;
zipf->z.dir_size = 0;
zipf->z.central_directory = NULL;
return -1;
}
else
{
if (read_zip_archive (&zipf->z) != 0)
return -2; /* This however should be an error - FIXME */
}
break;
}
if (strcmp (zipf->name, zipfile) == 0)
break;
}
if (!zipmember)
return 0;
len = strlen (zipmember);
zipd = (struct ZipDirectory*) zipf->z.central_directory;
for (i = 0; i < zipf->z.count; i++, zipd = ZIPDIR_NEXT (zipd))
{
if (len == zipd->filename_length &&
strncmp (ZIPDIR_FILENAME (zipd), zipmember, len) == 0)
{
JCF_ZERO (jcf);
jcf->buffer = ALLOC (zipd->size);
jcf->buffer_end = jcf->buffer + zipd->size;
jcf->read_ptr = jcf->buffer;
jcf->read_end = jcf->buffer_end;
jcf->filbuf = jcf_unexpected_eof;
jcf->filename = (char *) strdup (zipfile);
jcf->classname = (char *) strdup (zipmember);
jcf->zipd = (void *)zipd;
if (lseek (zipf->z.fd, zipd->filestart, 0) < 0
|| read (zipf->z.fd, jcf->buffer, zipd->size) != zipd->size)
return -2;
return 0;
}
}
return -1;
}
#endif /* ENABLE_UNZIP */
#if JCF_USE_STDIO
char*
DEFUN(open_class, (filename, jcf, stream),
char *filename AND JCF *jcf AND FILE* stream)
{
if (jcf)
{
JCF_ZERO (jcf);
jcf->buffer = NULL;
jcf->buffer_end = NULL;
jcf->read_ptr = NULL;
jcf->read_end = NULL;
jcf->read_state = stream;
jcf->filbuf = jcf_filbuf_from_stdio;
}
else
fclose (stream);
return filename;
}
#else
char*
DEFUN(open_class, (filename, jcf, fd),
char *filename AND JCF *jcf AND int fd)
{
if (jcf)
{
struct stat stat_buf;
if (fstat (fd, &stat_buf) != 0
|| ! S_ISREG (stat_buf.st_mode))
{
perror ("Could not figure length of .class file");
return NULL;
}
JCF_ZERO (jcf);
jcf->buffer = ALLOC (stat_buf.st_size);
jcf->buffer_end = jcf->buffer + stat_buf.st_size;
jcf->read_ptr = jcf->buffer;
jcf->read_end = jcf->buffer_end;
jcf->read_state = NULL;
jcf->filename = filename;
if (read (fd, jcf->buffer, stat_buf.st_size) != stat_buf.st_size)
{
perror ("Failed to read .class file");
return NULL;
}
close (fd);
jcf->filbuf = jcf_unexpected_eof;
}
else
close (fd);
return filename;
}
#endif
char *
DEFUN(find_classfile, (filename_length, jcf),
char *filename AND JCF *jcf)
{
#if JCF_USE_STDIO
FILE *stream = fopen (filename, "rb");
if (stream == NULL)
return NULL;
return open_class (arg, jcf, stream);
#else
int fd = open (filename, O_RDONLY | O_BINARY);
if (fd < 0)
return NULL;
return open_class (filename, jcf, fd);
#endif
}
/* Returns a freshly malloc'd string with the fully qualified pathname
of the .class file for the class CLASSNAME. Returns NULL on
failure. If JCF != NULL, it is suitably initialized. With
DO_CLASS_FILE set to 1, search a .class/.java file named after
CLASSNAME, otherwise, search a ZIP directory entry named after
CLASSNAME. */
char *
DEFUN(find_class, (classname, classname_length, jcf, do_class_file),
const char *classname AND int classname_length AND JCF *jcf AND int do_class_file)
{
#if JCF_USE_STDIO
FILE *stream;
#else
int fd;
#endif
int i, j, k, java, class;
struct stat java_buf, class_buf;
/* Allocate and zero out the buffer, since we don't explicitly put a
null pointer when we're copying it below. */
int buflen = strlen (classpath) + classname_length + 10;
char *buffer = (char *) ALLOC (buflen);
bzero (buffer, buflen);
jcf->java_source = jcf->outofsynch = 0;
for (j = 0; classpath[j] != '\0'; )
{
for (i = 0; classpath[j] != ':' && classpath[j] != '\0'; i++, j++)
buffer[i] = classpath[j];
if (classpath[j] == ':')
j++;
if (i > 0) /* Empty directory is redundant */
{
int dir_len;
if (buffer[i-1] != '/')
buffer[i++] = '/';
dir_len = i-1;
for (k = 0; k < classname_length; k++, i++)
{
char ch = classname[k];
buffer[i] = ch == '.' ? '/' : ch;
}
if (do_class_file)
strcpy (buffer+i, ".class");
#if ENABLE_UNZIP
if (dir_len > 4
&& buffer[dir_len-4] == '.' && buffer[dir_len-3] == 'z'
&& buffer[dir_len-2] == 'i' && buffer[dir_len-1] == 'p')
{
int err_code;
JCF _jcf;
if (!do_class_file)
strcpy (buffer+i, "/");
buffer[dir_len] = '\0';
if (do_class_file)
SOURCE_FRONTEND_DEBUG
(("Trying [...%s]:%s",
&buffer[dir_len-(dir_len > 15 ? 15 : dir_len)],
buffer+dir_len+1));
if (jcf == NULL)
jcf = &_jcf;
err_code = open_in_zip (jcf, buffer, buffer+dir_len+1);
if (err_code == 0)
{
if (!do_class_file)
jcf->seen_in_zip = 1;
else
{
buffer[dir_len] = '(';
strcpy (buffer+i, ".class)");
}
if (jcf == &_jcf)
JCF_FINISH (jcf);
return buffer;
}
else
continue;
}
#endif
/* If we do directories, do them here */
if (!do_class_file)
{
struct stat dir_buff;
int dir;
buffer[i] = '\0'; /* Was previously unterminated here. */
if (!(dir = stat (buffer, &dir_buff)))
{
jcf->seen_in_zip = 0;
goto found;
}
}
/* Check for out of synch .class/.java files */
class = stat (buffer, &class_buf);
strcpy (buffer+i, ".java");
java = stat (buffer, &java_buf);
if ((!java && !class) && java_buf.st_mtime >= class_buf.st_mtime)
jcf->outofsynch = 1;
#if JCF_USE_STDIO
if (!class)
{
strcpy (buffer+i, ".class");
SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
stream = fopen (buffer, "rb");
if (stream)
goto found;
}
/* Give .java a try, if necessary */
if (!java)
{
strcpy (buffer+i, ".java");
SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
stream = fopen (buffer, "r");
if (stream)
{
jcf->java_source = 1;
goto found;
}
}
#else
if (!class)
{
strcpy (buffer+i, ".class");
SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
fd = open (buffer, O_RDONLY | O_BINARY);
if (fd >= 0)
goto found;
}
/* Give .java a try, if necessary */
if (!java)
{
if (do_class_file)
strcpy (buffer+i, ".java");
SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
fd = open (buffer, O_RDONLY | O_BINARY);
if (fd >= 0)
{
jcf->java_source = 1;
goto found;
}
}
#endif
}
}
free (buffer);
return NULL;
found:
#if JCF_USE_STDIO
if (jcf->java_source)
return NULL; /* FIXME */
else
return open_class (buffer, jcf, stream);
#else
if (jcf->java_source)
{
JCF_ZERO (jcf); /* JCF_FINISH relies on this */
jcf->java_source = 1;
jcf->filename = (char *) strdup (buffer);
close (fd); /* We use STDIO for source file */
}
else if (do_class_file)
buffer = open_class (buffer, jcf, fd);
jcf->classname = (char *) ALLOC (classname_length + 1);
strncpy (jcf->classname, classname, classname_length + 1);
jcf->classname = (char *) strdup (classname);
return buffer;
#endif
}
void
DEFUN(jcf_print_char, (stream, ch),
FILE *stream AND int ch)
{
switch (ch)
{
case '\'':
case '\\':
case '\"':
fprintf (stream, "\\%c", ch);
break;
case '\n':
fprintf (stream, "\\n");
break;
case '\t':
fprintf (stream, "\\t");
break;
case '\r':
fprintf (stream, "\\r");
break;
default:
if (ch >= ' ' && ch < 127)
putc (ch, stream);
else if (ch < 256)
fprintf (stream, "\\%03x", ch);
else
fprintf (stream, "\\u%04x", ch);
}
}
/* Print UTF8 string at STR of length LENGTH bytes to STREAM. */
void
DEFUN(jcf_print_utf8, (stream, str, length),
FILE *stream AND register unsigned char *str AND int length)
{
unsigned char* limit = str + length;
while (str < limit)
{
int ch = UTF8_GET (str, limit);
if (ch < 0)
{
fprintf (stream, "\\<invalid>");
return;
}
jcf_print_char (stream, ch);
}
}
/* Same as jcf_print_utf8, but print IN_CHAR as OUT_CHAR. */
void
DEFUN(jcf_print_utf8_replace, (stream, str, length, in_char, out_char),
FILE *stream AND unsigned char *str AND int length
AND int in_char AND int out_char)
{
int i;/* FIXME - actually handle Unicode! */
for (i = 0; i < length; i++)
{
int ch = str[i];
jcf_print_char (stream, ch == in_char ? out_char : ch);
}
}
/* Check that all the cross-references in the constant pool are
valid. Returns 0 on success.
Otherwise, returns the index of the (first) invalid entry. */
int
DEFUN(verify_constant_pool, (jcf),
JCF *jcf)
{
int i, n;
for (i = 1; i < JPOOL_SIZE (jcf); i++)
{
switch (JPOOL_TAG (jcf, i))
{
case CONSTANT_NameAndType:
n = JPOOL_USHORT2 (jcf, i);
if (n <= 0 || n >= JPOOL_SIZE(jcf)
|| JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
return i;
/* ... fall through ... */
case CONSTANT_Class:
case CONSTANT_String:
n = JPOOL_USHORT1 (jcf, i);
if (n <= 0 || n >= JPOOL_SIZE(jcf)
|| JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
return i;
break;
case CONSTANT_Fieldref:
case CONSTANT_Methodref:
case CONSTANT_InterfaceMethodref:
n = JPOOL_USHORT1 (jcf, i);
if (n <= 0 || n >= JPOOL_SIZE(jcf)
|| JPOOL_TAG (jcf, n) != CONSTANT_Class)
return i;
n = JPOOL_USHORT2 (jcf, i);
if (n <= 0 || n >= JPOOL_SIZE(jcf)
|| JPOOL_TAG (jcf, n) != CONSTANT_NameAndType)
return i;
break;
case CONSTANT_Long:
case CONSTANT_Double:
i++;
break;
case CONSTANT_Float:
case CONSTANT_Integer:
case CONSTANT_Utf8:
case CONSTANT_Unicode:
break;
default:
return i;
}
}
return 0;
}
void
DEFUN(format_uint, (buffer, value, base),
char *buffer AND uint64 value AND int base)
{
#define WRITE_BUF_SIZE (4 + sizeof(uint64) * 8)
char buf[WRITE_BUF_SIZE];
register char *buf_ptr = buf+WRITE_BUF_SIZE; /* End of buf. */
int chars_written;
int i;
/* Now do the actual conversion, placing the result at the *end* of buf. */
/* Note this code does not pretend to be optimized. */
do {
int digit = value % base;
static char digit_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
*--buf_ptr = digit_chars[digit];
value /= base;
} while (value != 0);
chars_written = buf+WRITE_BUF_SIZE - buf_ptr;
for (i = 0; i < chars_written; i++)
buffer[i] = *buf_ptr++;
buffer[i] = 0;
}
void
DEFUN(format_int, (buffer, value, base),
char *buffer AND jlong value AND int base)
{
uint64 abs_value;
if (value < 0)
{
abs_value = -(uint64)value;
*buffer++ = '-';
}
else
abs_value = (uint64) value;
format_uint (buffer, abs_value, base);
}

917
gcc/java/jcf-parse.c Normal file
View file

@ -0,0 +1,917 @@
/* Parser for Java(TM) .class files.
Copyright (C) 1996 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC 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.
GNU CC 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, 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. */
/* Written by Per Bothner <bothner@cygnus.com> */
#include <stdio.h>
#include <ctype.h>
#include "config.h"
#include "tree.h"
#include "obstack.h"
#include "flags.h"
#include "java-except.h"
#include "input.h"
#include "java-tree.h"
/* A CONSTANT_Utf8 element is converted to an IDENTIFIER_NODE at parse time. */
#define JPOOL_UTF(JCF, INDEX) CPOOL_UTF(&(JCF)->cpool, INDEX)
#define JPOOL_UTF_LENGTH(JCF, INDEX) IDENTIFIER_LENGTH (JPOOL_UTF (JCF, INDEX))
#define JPOOL_UTF_DATA(JCF, INDEX) \
((unsigned char*) IDENTIFIER_POINTER (JPOOL_UTF (JCF, INDEX)))
#define HANDLE_CONSTANT_Utf8(JCF, INDEX, LENGTH) \
do { \
unsigned char save; unsigned char *text; \
JCF_FILL (JCF, (LENGTH)+1); /* Make sure we read 1 byte beyond string. */ \
text = (JCF)->read_ptr; \
save = text[LENGTH]; \
text[LENGTH] = 0; \
(JCF)->cpool.data[INDEX] = (jword) get_identifier (text); \
text[LENGTH] = save; \
JCF_SKIP (JCF, LENGTH); } while (0)
#include "jcf.h"
#ifdef __STDC__
/* For getenv */
#include <stdlib.h>
#endif
#ifndef SEEK_SET
#include <unistd.h>
#endif
extern struct obstack *saveable_obstack;
extern struct obstack temporary_obstack;
extern struct obstack permanent_obstack;
/* The class we are currently processing. */
tree current_class = NULL_TREE;
/* The class we started with. */
tree main_class = NULL_TREE;
/* The FIELD_DECL for the current field. */
static tree current_field = NULL_TREE;
static tree current_method = NULL_TREE;
static tree give_name_to_class PROTO ((JCF *jcf, int index));
void parse_zip_file_entries (void);
void process_zip_dir();
/* Source file compilation declarations */
static void parse_source_file ();
extern int java_error_count;
#define java_parse_abort_on_error() \
{ \
if (java_error_count) \
{ \
java_report_errors (); \
java_pop_parser_context (); \
return; \
} \
}
/* Handle "SourceFile" attribute. */
void
set_source_filename (jcf, index)
JCF *jcf;
int index;
{
tree sfname_id = get_name_constant (jcf, index);
char *sfname = IDENTIFIER_POINTER (sfname_id);
if (input_filename != NULL)
{
int old_len = strlen (input_filename);
int new_len = IDENTIFIER_LENGTH (sfname_id);
/* Use the current input_filename (derived from the class name)
if it has a directory prefix, but otherwise matches sfname. */
if (old_len > new_len
&& strcmp (sfname, input_filename + old_len - new_len) == 0
&& (input_filename[old_len - new_len - 1] == '/'
|| input_filename[old_len - new_len - 1] == '\\'))
return;
}
input_filename = sfname;
DECL_SOURCE_FILE (TYPE_NAME (current_class)) = sfname;
if (current_class == main_class) main_input_filename = input_filename;
}
#define HANDLE_SOURCEFILE(INDEX) set_source_filename (jcf, INDEX)
#define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \
{ tree super_class = SUPER==0 ? NULL_TREE : get_class_constant (jcf, SUPER); \
current_class = give_name_to_class (jcf, THIS); \
set_super_info (ACCESS_FLAGS, current_class, super_class, INTERFACES_COUNT);}
#define HANDLE_CLASS_INTERFACE(INDEX) \
add_interface (current_class, get_class_constant (jcf, INDEX))
#define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
{ int sig_index = SIGNATURE; \
current_field = add_field (current_class, get_name_constant (jcf, NAME), \
parse_signature (jcf, sig_index), ACCESS_FLAGS); \
set_java_signature (TREE_TYPE (current_field), JPOOL_UTF (jcf, sig_index)); }
#define HANDLE_END_FIELDS() \
(current_field = NULL_TREE)
#define HANDLE_CONSTANTVALUE(INDEX) \
{ tree constant; int index = INDEX; \
if (JPOOL_TAG (jcf, index) == CONSTANT_String) { \
tree name = get_name_constant (jcf, JPOOL_USHORT1 (jcf, index)); \
constant = build_utf8_ref (name); \
} \
else \
constant = get_constant (jcf, index); \
set_constant_value (current_field, constant); }
#define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
(current_method = add_method (current_class, ACCESS_FLAGS, \
get_name_constant (jcf, NAME), \
get_name_constant (jcf, SIGNATURE)), \
DECL_LOCALVARIABLES_OFFSET (current_method) = 0, \
DECL_LINENUMBERS_OFFSET (current_method) = 0)
#define HANDLE_END_METHODS() \
{ tree handle_type = CLASS_TO_HANDLE_TYPE (current_class); \
if (handle_type != current_class) layout_type (handle_type); }
#define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
{ DECL_MAX_STACK (current_method) = (MAX_STACK); \
DECL_MAX_LOCALS (current_method) = (MAX_LOCALS); \
DECL_CODE_LENGTH (current_method) = (CODE_LENGTH); \
DECL_CODE_OFFSET (current_method) = JCF_TELL (jcf); }
#define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \
{ int n = (COUNT); \
DECL_LOCALVARIABLES_OFFSET (current_method) = JCF_TELL (jcf) - 2; \
JCF_SKIP (jcf, n * 10); }
#define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
{ int n = (COUNT); \
DECL_LINENUMBERS_OFFSET (current_method) = JCF_TELL (jcf) - 2; \
JCF_SKIP (jcf, n * 4); }
#include "jcf-reader.c"
static int yydebug;
tree
parse_signature (jcf, sig_index)
JCF *jcf;
int sig_index;
{
if (sig_index <= 0 || sig_index >= JPOOL_SIZE(jcf)
|| JPOOL_TAG (jcf, sig_index) != CONSTANT_Utf8)
fatal ("invalid field/method signature");
else
{
return parse_signature_string (JPOOL_UTF_DATA (jcf, sig_index),
JPOOL_UTF_LENGTH (jcf, sig_index));
}
}
void
init_lex ()
{
/* Make identifier nodes long enough for the language-specific slots. */
set_identifier_size (sizeof (struct lang_identifier));
}
void
set_yydebug (value)
int value;
{
yydebug = value;
}
tree
get_constant (jcf, index)
JCF *jcf;
int index;
{
tree value;
int tag;
if (index <= 0 || index >= JPOOL_SIZE(jcf))
goto bad;
tag = JPOOL_TAG (jcf, index);
if ((tag & CONSTANT_ResolvedFlag) || tag == CONSTANT_Utf8)
return (tree) jcf->cpool.data[index];
push_obstacks (&permanent_obstack, &permanent_obstack);
switch (tag)
{
case CONSTANT_Integer:
{
jint num = JPOOL_INT(jcf, index);
value = build_int_2 (num, num < 0 ? -1 : 0);
TREE_TYPE (value) = int_type_node;
break;
}
case CONSTANT_Long:
{
jint num = JPOOL_INT (jcf, index);
HOST_WIDE_INT lo, hi;
lshift_double (num, 0, 32, 64, &lo, &hi, 0);
num = JPOOL_INT (jcf, index+1);
add_double (lo, hi, num, 0, &lo, &hi);
value = build_int_2 (lo, hi);
TREE_TYPE (value) = long_type_node;
force_fit_type (value, 0);
break;
}
#if TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
case CONSTANT_Float:
{
jint num = JPOOL_INT(jcf, index);
REAL_VALUE_TYPE d;
#ifdef REAL_ARITHMETIC
d = REAL_VALUE_FROM_TARGET_SINGLE (num);
#else
union { float f; jint i; } u;
u.i = num;
d = u.f;
#endif
value = build_real (float_type_node, d);
break;
}
case CONSTANT_Double:
{
HOST_WIDE_INT num[2];
REAL_VALUE_TYPE d;
HOST_WIDE_INT lo, hi;
num[0] = JPOOL_INT (jcf, index);
lshift_double (num[0], 0, 32, 64, &lo, &hi, 0);
num[0] = JPOOL_INT (jcf, index+1);
add_double (lo, hi, num[0], 0, &lo, &hi);
if (FLOAT_WORDS_BIG_ENDIAN)
{
num[0] = hi;
num[1] = lo;
}
else
{
num[0] = lo;
num[1] = hi;
}
#ifdef REAL_ARITHMETIC
d = REAL_VALUE_FROM_TARGET_DOUBLE (num);
#else
union { double d; jint i[2]; } u;
u.i[0] = (jint) num[0];
u.i[1] = (jint) num[1];
d = u.d;
#endif
value = build_real (double_type_node, d);
break;
}
#endif /* TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT */
case CONSTANT_String:
{
extern struct obstack *expression_obstack;
tree name = get_name_constant (jcf, JPOOL_USHORT1 (jcf, index));
char *utf8_ptr = IDENTIFIER_POINTER (name);
unsigned char *str_ptr;
int utf8_len = IDENTIFIER_LENGTH (name);
unsigned char *str = (unsigned char*)utf8_ptr;
int i = utf8_len;
int str_len;
/* Count the number of Unicode characters in the string,
while checking for a malformed Utf8 string. */
for (str_len = 0; i > 0; str_len++)
{
int char_len = UT8_CHAR_LENGTH (*str);
if (char_len < 0 || char_len > 2 || char_len > i)
fatal ("bad string constant");
str += char_len;
i -= char_len;
}
value = make_node (STRING_CST);
TREE_STRING_LENGTH (value) = 2 * str_len;
TREE_STRING_POINTER (value)
= obstack_alloc (expression_obstack, 2 * str_len);
str_ptr = (unsigned char *) TREE_STRING_POINTER (value);
str = (unsigned char*)utf8_ptr;
for (i = 0; i < str_len; i++)
{
int char_value;
int char_len = UT8_CHAR_LENGTH (*str);
switch (char_len)
{
case 1:
char_value = *str++;
break;
case 2:
char_value = *str++ & 0x1F;
char_value = (char_value << 6) | (*str++ & 0x3F);
break;
case 3:
char_value = *str_ptr++ & 0x0F;
char_value = (char_value << 6) | (*str++ & 0x3F);
char_value = (char_value << 6) | (*str++ & 0x3F);
break;
default:
goto bad;
}
if (BYTES_BIG_ENDIAN)
{
*str_ptr++ = char_value >> 8;
*str_ptr++ = char_value & 0xFF;
}
else
{
*str_ptr++ = char_value & 0xFF;
*str_ptr++ = char_value >> 8;
}
}
}
break;
default:
goto bad;
}
pop_obstacks ();
JPOOL_TAG(jcf, index) = tag | CONSTANT_ResolvedFlag;
jcf->cpool.data [index] = (jword) value;
return value;
bad:
fatal ("bad value constant type %d, index %d",
JPOOL_TAG( jcf, index ), index);
}
tree
get_name_constant (jcf, index)
JCF *jcf;
int index;
{
tree name = get_constant (jcf, index);
if (TREE_CODE (name) != IDENTIFIER_NODE)
fatal ("bad nameandtype index %d", index);
return name;
}
static tree
give_name_to_class (jcf, i)
JCF *jcf;
int i;
{
if (i <= 0 || i >= JPOOL_SIZE(jcf)
|| JPOOL_TAG (jcf, i) != CONSTANT_Class)
fatal ("bad class index %d", i);
else
{
tree this_class;
int j = JPOOL_USHORT1 (jcf, i);
/* verify_constant_pool confirmed that j is a CONSTANT_Utf8. */
tree class_name = unmangle_classname (JPOOL_UTF_DATA (jcf, j),
JPOOL_UTF_LENGTH (jcf, j));
this_class = lookup_class (class_name);
input_filename = DECL_SOURCE_FILE (TYPE_NAME (this_class));
lineno = 0;
if (main_input_filename == NULL && jcf == main_jcf)
main_input_filename = input_filename;
jcf->cpool.data[i] = (jword) this_class;
JPOOL_TAG (jcf, i) = CONSTANT_ResolvedClass;
return this_class;
}
}
/* Get the class of the CONSTANT_Class whose constant pool index is I. */
tree
get_class_constant (JCF *jcf , int i)
{
tree type;
if (i <= 0 || i >= JPOOL_SIZE(jcf)
|| (JPOOL_TAG (jcf, i) & ~CONSTANT_ResolvedFlag) != CONSTANT_Class)
fatal ("bad class index %d", i);
if (JPOOL_TAG (jcf, i) != CONSTANT_ResolvedClass)
{
int name_index = JPOOL_USHORT1 (jcf, i);
/* verify_constant_pool confirmed that name_index is a CONSTANT_Utf8. */
char *name = JPOOL_UTF_DATA (jcf, name_index);
int nlength = JPOOL_UTF_LENGTH (jcf, name_index);
if (name[0] == '[') /* Handle array "classes". */
type = parse_signature_string (name, nlength);
else
{
tree cname = unmangle_classname (name, nlength);
type = lookup_class (cname);
}
jcf->cpool.data[i] = (jword) type;
JPOOL_TAG (jcf, i) = CONSTANT_ResolvedClass;
}
else
type = (tree) jcf->cpool.data[i];
return type;
}
void
fix_classpath ()
{
static char default_path[] = DEFAULT_CLASS_PATH;
if (classpath == NULL)
{
classpath = (char *) getenv ("CLASSPATH");
if (classpath == NULL)
{
warning ("CLASSPATH not set");
classpath = default_path;
}
}
}
void
DEFUN(jcf_out_of_synch, (jcf),
JCF *jcf)
{
char *source = strdup (jcf->filename);
int i = strlen (source);
while (source[i] != '.')
i--;
source [i] = '\0';
warning ("Class file `%s' out of synch with `%s.java'",
jcf->filename, source);
free (source);
}
/* Load CLASS_OR_NAME. CLASS_OR_NAME can be a mere identifier if
called from the parser, otherwise it's a RECORD_TYPE node. If
VERBOSE is 1, print error message on failure to load a class. */
void
load_class (class_or_name, verbose)
tree class_or_name;
int verbose;
{
JCF this_jcf, *jcf;
tree name = (TREE_CODE (class_or_name) == IDENTIFIER_NODE ?
class_or_name : DECL_NAME (TYPE_NAME (class_or_name)));
tree save_current_class = current_class;
char *save_input_filename = input_filename;
JCF *save_current_jcf = current_jcf;
long saved_pos;
if (current_jcf->read_state)
saved_pos = ftell (current_jcf->read_state);
push_obstacks (&permanent_obstack, &permanent_obstack);
if (!classpath)
fix_classpath ();
/* Search in current zip first. */
if (find_in_current_zip (IDENTIFIER_POINTER (name),
IDENTIFIER_LENGTH (name), &jcf) == 0)
if (find_class (IDENTIFIER_POINTER (name), IDENTIFIER_LENGTH (name),
&this_jcf, 1) == 0)
{
if (verbose)
{
error ("Cannot find class file class %s.",
IDENTIFIER_POINTER (name));
TYPE_SIZE (class_or_name) = error_mark_node;
if (!strcmp (classpath, DEFAULT_CLASS_PATH))
fatal ("giving up");
pop_obstacks (); /* FIXME: one pop_obstack() per function */
}
return;
}
else
{
this_jcf.seen_in_zip = 0;
current_jcf = &this_jcf;
if (this_jcf.outofsynch)
jcf_out_of_synch (current_jcf);
}
else
current_jcf = jcf;
if (current_jcf->java_source)
jcf_parse_source (current_jcf);
else {
int saved_lineno = lineno;
input_filename = current_jcf->filename;
jcf_parse (current_jcf);
lineno = saved_lineno;
}
if (!current_jcf->seen_in_zip)
JCF_FINISH (current_jcf);
/* DECL_IGNORED_P (TYPE_NAME (class_or_name)) = 1;*/
pop_obstacks ();
current_class = save_current_class;
input_filename = save_input_filename;
current_jcf = save_current_jcf;
if (current_jcf->read_state)
fseek (current_jcf->read_state, saved_pos, SEEK_SET);
}
/* Parse a source file when JCF refers to a source file. This piece
needs further work as far as error handling and report. */
int
jcf_parse_source (jcf)
JCF *jcf;
{
java_parser_context_save_global ();
input_filename = current_jcf->filename;
if (!(finput = fopen (input_filename, "r")))
fatal ("input file `%s' just disappeared - jcf_parse_source",
input_filename);
parse_source_file (1); /* Parse only */
if (current_class && TREE_TYPE (current_class))
CLASS_FROM_SOURCE_P (TREE_TYPE (current_class)) = 1;
fclose (finput);
java_parser_context_restore_global ();
}
/* Parse the .class file JCF. */
int
jcf_parse (jcf)
JCF* jcf;
{
int i, code;
if (jcf_parse_preamble (jcf) != 0)
fatal ("Not a valid Java .class file.\n");
code = jcf_parse_constant_pool (jcf);
if (code != 0)
fatal ("error while parsing constant pool");
code = verify_constant_pool (jcf);
if (code > 0)
fatal ("error in constant pool entry #%d\n", code);
jcf_parse_class (jcf);
if (main_class == NULL_TREE)
main_class = current_class;
if (! quiet_flag && TYPE_NAME (current_class))
fprintf (stderr, " class %s",
IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (current_class))));
CLASS_LOADED_P (current_class) = 1;
for (i = 1; i < JPOOL_SIZE(jcf); i++)
{
switch (JPOOL_TAG (jcf, i))
{
case CONSTANT_Class:
get_class_constant (jcf, i);
break;
}
}
code = jcf_parse_fields (jcf);
if (code != 0)
fatal ("error while parsing fields");
code = jcf_parse_methods (jcf);
if (code != 0)
fatal ("error while parsing methods");
code = jcf_parse_final_attributes (jcf);
if (code != 0)
fatal ("error while parsing final attributes");
/* The fields of class_type_node are already in correct order. */
if (current_class != class_type_node && current_class != object_type_node)
TYPE_FIELDS (current_class) = nreverse (TYPE_FIELDS (current_class));
push_obstacks (&permanent_obstack, &permanent_obstack);
layout_class (current_class);
pop_obstacks ();
}
void
init_outgoing_cpool ()
{
current_constant_pool_data_ref = NULL_TREE;
if (outgoing_cpool == NULL)
{
static CPool outgoing_cpool_buffer;
outgoing_cpool = &outgoing_cpool_buffer;
CPOOL_INIT(outgoing_cpool);
}
else
{
CPOOL_REINIT(outgoing_cpool);
}
}
void
parse_class_file ()
{
tree method;
char *save_input_filename = input_filename;
int save_lineno = lineno;
input_filename = DECL_SOURCE_FILE (TYPE_NAME (current_class));
lineno = 0;
debug_start_source_file (input_filename);
init_outgoing_cpool ();
for ( method = TYPE_METHODS (CLASS_TO_HANDLE_TYPE (current_class));
method != NULL_TREE; method = TREE_CHAIN (method))
{
JCF *jcf = current_jcf;
if (METHOD_NATIVE (method) || METHOD_ABSTRACT (method))
continue;
if (DECL_CODE_OFFSET (method) == 0)
{
error ("missing Code attribute");
continue;
}
lineno = 0;
if (DECL_LINENUMBERS_OFFSET (method))
{
register int i;
register unsigned char *ptr;
JCF_SEEK (jcf, DECL_LINENUMBERS_OFFSET (method));
linenumber_count = i = JCF_readu2 (jcf);
linenumber_table = ptr = jcf->read_ptr;
for (ptr += 2; --i >= 0; ptr += 4)
{
int line = GET_u2 (ptr);
/* Set initial lineno lineno to smallest linenumber.
* Needs to be set before init_function_start. */
if (lineno == 0 || line < lineno)
lineno = line;
}
}
else
{
linenumber_table = NULL;
linenumber_count = 0;
}
start_java_method (method);
give_name_to_locals (jcf);
/* Actually generate code. */
expand_byte_code (jcf, method);
end_java_method ();
}
if (flag_emit_class_files)
write_classfile (current_class);
make_class_data (current_class);
register_class ();
rest_of_decl_compilation (TYPE_NAME (current_class), (char*) 0, 1, 0);
debug_end_source_file (save_lineno);
input_filename = save_input_filename;
lineno = save_lineno;
}
/* Parse a source file, as pointed by the current JCF. If PARSE_ONLY
is non zero, we're not parsing a file found on the command line and
we skip things related to code generation. */
static void
parse_source_file (parse_only)
int parse_only;
{
lang_init_source (1); /* Error msgs have no method prototypes */
java_push_parser_context ();
java_init_lex (); /* Initialize the parser */
java_parse_abort_on_error ();
java_parse (); /* Parse and build partial tree nodes. */
java_parse_abort_on_error ();
java_complete_class (); /* Parse unsatisfied class decl. */
java_parse_abort_on_error ();
java_check_circular_reference (); /* Check on circular references */
java_parse_abort_on_error ();
java_check_methods (); /* Check the methods */
java_parse_abort_on_error ();
java_layout_classes ();
java_parse_abort_on_error ();
if (!parse_only)
{
lang_init_source (2); /* Error msgs have method prototypes */
java_complete_expand_methods (); /* Complete and expand method bodies */
java_parse_abort_on_error ();
java_expand_finals (); /* Expand and check the finals */
java_parse_abort_on_error ();
java_check_final (); /* Check unitialized final */
java_parse_abort_on_error ();
if (! flag_emit_class_files)
emit_register_class ();
java_report_errors (); /* Final step for this file */
}
if (flag_emit_class_files)
write_classfile (current_class);
java_pop_parser_context ();
}
int
yyparse ()
{
/* Everything migh be enclosed within a loop processing each file after
the other one. */
switch (jcf_figure_file_type (current_jcf))
{
case JCF_ZIP:
parse_zip_file_entries ();
emit_register_class ();
break;
case JCF_CLASS:
jcf_parse (current_jcf);
parse_class_file ();
emit_register_class ();
break;
case JCF_SOURCE:
parse_source_file (0); /* Parse and generate */
break;
}
return 0;
}
static struct ZipFileCache *localToFile;
/* Process all class entries found in the zip file. */
void
parse_zip_file_entries (void)
{
struct ZipDirectory *zdir;
int i;
for (i = 0, zdir = (ZipDirectory *)localToFile->z.central_directory;
i < localToFile->z.count; i++, zdir = ZIPDIR_NEXT (zdir))
{
tree class;
/* We don't need to consider those files. */
if (!zdir->size || !zdir->filename_offset)
continue;
class = lookup_class (get_identifier (ZIPDIR_FILENAME (zdir)));
current_jcf = TYPE_LANG_SPECIFIC (class)->jcf;
current_class = class;
if ( !CLASS_LOADED_P (class))
{
fseek (current_jcf->read_state, current_jcf->zip_offset, SEEK_SET);
jcf_parse (current_jcf);
}
input_filename = current_jcf->filename;
parse_class_file ();
FREE (current_jcf->buffer); /* No longer necessary */
/* Note: there is a way to free this buffer right after a class seen
in a zip file has been parsed. The idea is the set its jcf in such
a way that buffer will be reallocated the time the code for the class
will be generated. FIXME. */
}
}
/* Read all the entries of the zip file, creates a class and a JCF. Sets the
jcf up for further processing and link it to the created class. */
void process_zip_dir()
{
int i;
ZipDirectory *zdir;
for (i = 0, zdir = (ZipDirectory *)localToFile->z.central_directory;
i < localToFile->z.count; i++, zdir = ZIPDIR_NEXT (zdir))
{
char *class_name, *file_name, *class_name_in_zip_dir;
tree class;
JCF *jcf;
int j;
class_name_in_zip_dir = ZIPDIR_FILENAME (zdir);
/* We choose to not to process entries with a zero size or entries
not bearing the .class extention. */
if (!zdir->size || !zdir->filename_offset ||
strncmp (&class_name_in_zip_dir[zdir->filename_length-6],
".class", 6))
{
/* So it will be skipped in parse_zip_file_entries */
zdir->size = 0;
continue;
}
class_name = ALLOC (zdir->filename_length+1-6);
file_name = ALLOC (zdir->filename_length+1);
jcf = ALLOC (sizeof (JCF));
JCF_ZERO (jcf);
strncpy (class_name, class_name_in_zip_dir, zdir->filename_length-6);
class_name [zdir->filename_length-6] = '\0';
strncpy (file_name, class_name_in_zip_dir, zdir->filename_length);
file_name [zdir->filename_length] = '\0';
for (j=0; class_name[j]; j++)
class_name [j] = (class_name [j] == '/' ? '.' : class_name [j]);
/* Yes, we write back the true class name into the zip directory. */
strcpy (class_name_in_zip_dir, class_name);
zdir->filename_length = j;
class = lookup_class (get_identifier (class_name));
jcf->read_state = finput;
jcf->filbuf = jcf_filbuf_from_stdio;
jcf->seen_in_zip = 1;
jcf->java_source = 0;
jcf->zip_offset = zdir->filestart;
jcf->classname = class_name;
jcf->filename = file_name;
TYPE_LANG_SPECIFIC (class) =
(struct lang_type *) perm_calloc (1, sizeof (struct lang_type));
TYPE_LANG_SPECIFIC (class)->jcf = jcf;
}
}
/* Lookup class NAME and figure whether is a class already found in the current
zip file. */
int
DEFUN(find_in_current_zip, (name, length, jcf),
char *name AND int length AND JCF **jcf)
{
JCF *local_jcf;
tree class_name = maybe_get_identifier (name), class, icv;
if (!class_name)
return 0;
if (!(icv = IDENTIFIER_CLASS_VALUE (class_name)))
return 0;
class = TREE_TYPE (icv);
/* Doesn't have jcf specific info ? It's not ours */
if (!TYPE_LANG_SPECIFIC (class) || !TYPE_LANG_SPECIFIC (class)->jcf)
return 0;
*jcf = local_jcf = TYPE_LANG_SPECIFIC (class)->jcf;
fseek (local_jcf->read_state, local_jcf->zip_offset, SEEK_SET);
return 1;
}
/* Figure what kind of file we're dealing with */
int
DEFUN(jcf_figure_file_type, (jcf),
JCF *jcf)
{
unsigned char magic_string[4];
uint32 magic;
if (fread (magic_string, 1, 4, jcf->read_state) != 4)
jcf_unexpected_eof (jcf, 4);
fseek (jcf->read_state, 0L, SEEK_SET);
magic = GET_u4 (magic_string);
if (magic == 0xcafebabe)
return JCF_CLASS;
if (!open_in_zip (jcf, input_filename, NULL))
{
localToFile = ALLOC (sizeof (struct ZipFileCache));
bcopy (SeenZipFiles, localToFile, sizeof (struct ZipFileCache));
process_zip_dir (); /* Register all the class defined there */
return JCF_ZIP;
}
return JCF_SOURCE;
}

352
gcc/java/jcf-reader.c Normal file
View file

@ -0,0 +1,352 @@
/* This file read a Java(TM) .class file.
It is not stand-alone: It depends on tons of macros, and the
intent is you #include this file after you've defined the macros.
Copyright (C) 1996 Free Software Foundation, Inc.
This program 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.
This program 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, 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 "jcf.h"
#include "zipfile.h"
int
DEFUN(get_attribute, (jcf),
JCF *jcf)
{
uint16 attribute_name = (JCF_FILL (jcf, 6), JCF_readu2 (jcf));
uint32 attribute_length = JCF_readu4 (jcf);
uint32 start_pos = JCF_TELL(jcf);
int name_length;
unsigned char *name_data;
JCF_FILL (jcf, attribute_length);
if (attribute_name <= 0 || attribute_name >= JPOOL_SIZE(jcf))
return -2;
if (JPOOL_TAG (jcf, attribute_name) != CONSTANT_Utf8)
return -2;
name_length = JPOOL_UTF_LENGTH (jcf, attribute_name);
name_data = JPOOL_UTF_DATA (jcf, attribute_name);
#ifdef IGNORE_ATTRIBUTE
if (IGNORE_ATTRIBUTE (jcf, attribute_name, attribute_length))
{
JCF_SKIP (jcf, attribute_length);
}
else
#endif
#ifdef HANDLE_SOURCEFILE
if (name_length == 10 && memcmp (name_data, "SourceFile", 10) == 0)
{
uint16 sourcefile_index = JCF_readu2 (jcf);
HANDLE_SOURCEFILE(sourcefile_index);
}
else
#endif
#ifdef HANDLE_CONSTANTVALUE
if (name_length == 13 && memcmp (name_data, "ConstantValue", 13) == 0)
{
uint16 constantvalue_index = JCF_readu2 (jcf);
if (constantvalue_index <= 0 || constantvalue_index >= JPOOL_SIZE(jcf))
return -2;
HANDLE_CONSTANTVALUE(constantvalue_index);
}
else
#endif
#ifdef HANDLE_CODE_ATTRIBUTE
if (name_length == 4 && memcmp (name_data, "Code", 4) == 0)
{
uint16 j;
uint16 max_stack = JCF_readu2 (jcf);
uint16 max_locals = JCF_readu2 (jcf);
uint32 code_length = JCF_readu4 (jcf);
uint16 exception_table_length, attributes_count;
if (code_length + 12 > attribute_length)
return -1;
HANDLE_CODE_ATTRIBUTE(max_stack, max_locals, code_length);
JCF_SKIP (jcf, code_length);
exception_table_length = JCF_readu2 (jcf);
if (code_length + 8 * exception_table_length + 12 > attribute_length)
return -1;
JCF_SKIP (jcf, 2 * 4 * exception_table_length);
attributes_count = JCF_readu2 (jcf);
for (j = 0; j < attributes_count; j++)
{
int code = get_attribute (jcf);
if (code != 0)
return code;
}
}
else
#endif /* HANDLE_CODE_ATTRIBUTE */
#ifdef HANDLE_EXCEPTIONS_ATTRIBUTE
if (name_length == 10 && memcmp (name_data, "Exceptions", 10) == 0)
{
uint16 count = JCF_readu2 (jcf);
HANDLE_EXCEPTIONS_ATTRIBUTE (count);
}
else
#endif
#ifdef HANDLE_LINENUMBERTABLE_ATTRIBUTE
if (name_length == 15 && memcmp (name_data, "LineNumberTable", 15) == 0)
{
uint16 count = JCF_readu2 (jcf);
HANDLE_LINENUMBERTABLE_ATTRIBUTE (count);
}
else
#endif
#ifdef HANDLE_LOCALVARIABLETABLE_ATTRIBUTE
if (name_length == 18 && memcmp (name_data, "LocalVariableTable", 18) == 0)
{
uint16 count = JCF_readu2 (jcf);
HANDLE_LOCALVARIABLETABLE_ATTRIBUTE (count);
}
else
#endif
{
#ifdef PROCESS_OTHER_ATTRIBUTE
PROCESS_OTHER_ATTRIBUTE(jcf, attribute_name, attribute_length);
#else
JCF_SKIP (jcf, attribute_length);
#endif
}
if (start_pos + attribute_length != JCF_TELL(jcf))
return -1;
return 0;
}
/* Read and handle the pre-amble. */
int
DEFUN(jcf_parse_preamble, (jcf),
JCF* jcf)
{
uint32 magic = (JCF_FILL (jcf, 8), JCF_readu4 (jcf));
uint16 minor_version = JCF_readu2 (jcf);
uint16 major_version = JCF_readu2 (jcf);
#ifdef HANDLE_MAGIC
HANDLE_MAGIC (magic, minor_version, major_version);
#endif
if (magic != 0xcafebabe)
return -1;
else
return 0;
}
/* Read and handle the constant pool.
Return 0 if OK.
Return -2 if a bad cross-reference (index of other constant) was seen.
*/
int
DEFUN(jcf_parse_constant_pool, (jcf),
JCF* jcf)
{
int i, n;
JPOOL_SIZE (jcf) = (JCF_FILL (jcf, 2), JCF_readu2 (jcf));
jcf->cpool.tags = ALLOC (JPOOL_SIZE (jcf));
jcf->cpool.data = ALLOC (sizeof (jword) * JPOOL_SIZE (jcf));
jcf->cpool.tags[0] = 0;
#ifdef HANDLE_START_CONSTANT_POOL
HANDLE_START_CONSTANT_POOL (JPOOL_SIZE (jcf));
#endif
for (i = 1; i < (int) JPOOL_SIZE (jcf); i++)
{
int constant_kind;
/* Make sure at least 9 bytes are available. This is enough
for all fixed-sized constant pool entries (so we don't need many
more JCF_FILL calls below), but is is small enough that
we are guaranteed to not hit EOF (in a valid .class file). */
JCF_FILL (jcf, 9);
constant_kind = JCF_readu (jcf);
jcf->cpool.tags[i] = constant_kind;
switch (constant_kind)
{
case CONSTANT_String:
case CONSTANT_Class:
jcf->cpool.data[i] = JCF_readu2 (jcf);
break;
case CONSTANT_Fieldref:
case CONSTANT_Methodref:
case CONSTANT_InterfaceMethodref:
case CONSTANT_NameAndType:
jcf->cpool.data[i] = JCF_readu2 (jcf);
jcf->cpool.data[i] |= JCF_readu2 (jcf) << 16;
break;
case CONSTANT_Integer:
case CONSTANT_Float:
jcf->cpool.data[i] = JCF_readu4 (jcf);
break;
case CONSTANT_Long:
case CONSTANT_Double:
jcf->cpool.data[i] = JCF_readu4 (jcf);
i++; /* These take up two spots in the constant pool */
jcf->cpool.tags[i] = 0;
jcf->cpool.data[i] = JCF_readu4 (jcf);
break;
case CONSTANT_Utf8:
n = JCF_readu2 (jcf);
JCF_FILL (jcf, n);
#ifdef HANDLE_CONSTANT_Utf8
HANDLE_CONSTANT_Utf8(jcf, i, n);
#else
jcf->cpool.data[i] = JCF_TELL(jcf) - 2;
JCF_SKIP (jcf, n);
#endif
break;
default:
return i;
}
}
return 0;
}
/* Read various class flags and numbers. */
void
DEFUN(jcf_parse_class, (jcf),
JCF* jcf)
{
int i;
uint16 interfaces_count;
JCF_FILL (jcf, 8);
jcf->access_flags = JCF_readu2 (jcf);
jcf->this_class = JCF_readu2 (jcf);
jcf->super_class = JCF_readu2 (jcf);
interfaces_count = JCF_readu2 (jcf);
#ifdef HANDLE_CLASS_INFO
HANDLE_CLASS_INFO(jcf->access_flags, jcf->this_class, jcf->super_class, interfaces_count);
#endif
JCF_FILL (jcf, 2 * interfaces_count);
/* Read interfaces. */
for (i = 0; i < interfaces_count; i++)
{
uint16 index = JCF_readu2 (jcf);
#ifdef HANDLE_CLASS_INTERFACE
HANDLE_CLASS_INTERFACE (index);
#endif
}
}
/* Read fields. */
int
DEFUN(jcf_parse_fields, (jcf),
JCF* jcf)
{
int i, j;
uint16 fields_count;
JCF_FILL (jcf, 2);
fields_count = JCF_readu2 (jcf);
#ifdef HANDLE_START_FIELDS
HANDLE_START_FIELDS (fields_count);
#endif
for (i = 0; i < fields_count; i++)
{
uint16 access_flags = (JCF_FILL (jcf, 8), JCF_readu2 (jcf));
uint16 name_index = JCF_readu2 (jcf);
uint16 signature_index = JCF_readu2 (jcf);
uint16 attribute_count = JCF_readu2 (jcf);
#ifdef HANDLE_START_FIELD
HANDLE_START_FIELD (access_flags, name_index, signature_index,
attribute_count);
#endif
for (j = 0; j < attribute_count; j++)
{
int code = get_attribute (jcf);
if (code != 0)
return code;
}
#ifdef HANDLE_END_FIELD
HANDLE_END_FIELD ();
#endif
}
#ifdef HANDLE_END_FIELDS
HANDLE_END_FIELDS ();
#endif
return 0;
}
/* Read methods. */
int
DEFUN(jcf_parse_one_method, (jcf),
JCF* jcf)
{
int i;
uint16 access_flags = (JCF_FILL (jcf, 8), JCF_readu2 (jcf));
uint16 name_index = JCF_readu2 (jcf);
uint16 signature_index = JCF_readu2 (jcf);
uint16 attribute_count = JCF_readu2 (jcf);
#ifdef HANDLE_METHOD
HANDLE_METHOD(access_flags, name_index, signature_index, attribute_count);
#endif
for (i = 0; i < attribute_count; i++)
{
int code = get_attribute (jcf);
if (code != 0)
return code;
}
return 0;
}
int
DEFUN(jcf_parse_methods, (jcf),
JCF* jcf)
{
int i;
uint16 methods_count;
JCF_FILL (jcf, 2);
methods_count = JCF_readu2 (jcf);
#ifdef HANDLE_START_METHODS
HANDLE_START_METHODS (methods_count);
#endif
for (i = 0; i < methods_count; i++)
{
int code = jcf_parse_one_method (jcf);
if (code != 0)
return code;
}
#ifdef HANDLE_END_METHODS
HANDLE_END_METHODS ();
#endif
return 0;
}
/* Read attributes. */
int
DEFUN(jcf_parse_final_attributes, (jcf),
JCF *jcf)
{
int i;
uint16 attributes_count = (JCF_FILL (jcf, 2), JCF_readu2 (jcf));
#ifdef START_FINAL_ATTRIBUTES
START_FINAL_ATTRIBUTES (attributes_count)
#endif
for (i = 0; i < attributes_count; i++)
{
int code = get_attribute (jcf);
if (code != 0)
return code;
}
return 0;
}

964
gcc/java/jcf-write.c Normal file
View file

@ -0,0 +1,964 @@
/* Write out a Java(TM) class file.
Copyright (C) 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC 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.
GNU CC 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, 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 "tree.h"
#include "java-tree.h"
#include "jcf.h"
#include <stdio.h>
#include "obstack.h"
#undef AND
#include "rtl.h"
#include "java-opcodes.h"
#include "parse.h" /* for BLOCK_EXPR_BODY */
#include "buffer.h"
extern struct obstack temporary_obstack;
/* The buffer allocated for bytecode for the current method. */
struct buffer bytecode = NULL_BUFFER;
/* Make sure bytecode.data is big enough for at least N more bytes. */
#define RESERVE(N) \
do { if (bytecode.ptr + (N) > bytecode.limit) buffer_grow (&bytecode, N); } while (0)
/* Add a 1-byte instruction/operand I to bytecode.data,
assuming space has already been RESERVE'd. */
#define OP1(I) (*bytecode.ptr++ = (I))
/* Like OP1, but I is a 2-byte big endian integer. */
#define OP2(I) \
do { int _I = (I); OP1 (_I >> 8); OP1 (_I); } 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); } while (0)
/* The current stack size (stack pointer) in the current method. */
int code_SP = 0;
/* The largest extent of stack size (stack pointer) in the current method. */
int code_SP_max = 0;
CPool *code_cpool;
/* Macro to call each time we push I words on the JVM stack. */
#define NOTE_PUSH(I) \
do { code_SP += (I); if (code_SP > code_SP_max) code_SP_max = code_SP; } while (0)
/* Macro to call each time we pop I words from the JVM stack. */
#define NOTE_POP(I) \
do { code_SP -= (I); if (code_SP < 0) abort(); } while (0)
/* 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;
};
/* Utility macros for appending (big-endian) data to a buffer.
We assume a local variable 'ptr' points into where we want to
write next, and we assume enoygh space has been allocated. */
#define PUT1(X) (*ptr++ = (X))
#define PUT2(X) (PUT1((X) >> 8), PUT1((X) & 0xFF))
#define PUT4(X) (PUT2((X) >> 16), PUT2((X) & 0xFFFF))
#define PUTN(P, N) (bcopy(P, ptr, N), ptr += (N))
/* A buffer for storing line number entries for the current method. */
struct buffer linenumbers = NULL_BUFFER;
/* Append a line number entry for the given PC and LINE into
linenumbers.data. This will later before a LineNumberTable attribute. */
void
put_linenumber (pc, line)
int pc, line;
{
register unsigned char *ptr;
if (linenumbers.ptr == linenumbers.limit)
buffer_grow (&linenumbers, 4);
ptr = linenumbers.ptr;
PUT2 (pc);
PUT2 (line);
linenumbers.ptr = ptr;
}
/* The index of jvm local variable allocated for this DECL.
This is assign when generating .class files;
contrast DECL_LOCAL_SLOT_NUMBER whcih is set when *reading* a .class file.
(We don't allocate DECL_LANG_SPECIFIC for locals from Java sourc code.) */
#define DECL_LOCAL_INDEX(DECL) DECL_ALIGN(DECL)
struct localvar_info
{
tree decl;
int start_pc;
/* Offset in LocalVariableTable. */
int debug_offset;
};
struct buffer localvars = NULL_BUFFER;
#define localvar_buffer ((struct localvar_info*) localvars.data)
#define localvar_max ((struct localvar_info*) localvars.ptr - localvar_buffer)
/* A buffer for storing LocalVariableTable entries entries. */
struct buffer localvartable = NULL_BUFFER;
int
localvar_alloc (decl, start_pc)
tree decl;
int start_pc;
{
int wide = TYPE_IS_WIDE (TREE_TYPE (decl));
int index;
register struct localvar_info *info = (struct localvar_info*)localvars.data;
register struct localvar_info *limit = (struct localvar_info*)localvars.ptr;
for (index = 0; info < limit; index++, info++)
{
if (info->decl == NULL_TREE
&& (! wide || (info+1)->decl == NULL_TREE))
break;
}
if (info == limit)
{
buffer_grow (&localvars, sizeof (struct localvar_info));
info = (struct localvar_info*)localvars.data + index;
localvars.ptr = (unsigned char *) (info + 1 + wide);
}
info->decl = decl;
if (wide)
(info+1)->decl = TYPE_SECOND;
DECL_LOCAL_INDEX (decl) = index;
info->start_pc = start_pc;
if (DECL_NAME (decl) != NULL_TREE)
{
/* Generate debugging info. */
int i;
register unsigned char *ptr;
buffer_grow (&localvartable, 10);
ptr = localvartable.ptr;
info->debug_offset = ptr - localvartable.data;
PUT2 (start_pc);
PUT2 (0); /* length - fill in later */
i = find_utf8_constant (code_cpool, DECL_NAME (decl));
PUT2 (i); /* name_index*/
i = find_utf8_constant (code_cpool,
build_java_signature (TREE_TYPE (decl)));
PUT2 (i); /* descriptor_index */
PUT2 (index);
localvartable.ptr = ptr;
}
else
info->debug_offset = -1;
}
int
localvar_free (decl, end_pc)
tree decl;
int end_pc;
{
register unsigned char *ptr;
int index = DECL_LOCAL_INDEX (decl);
register struct localvar_info *info = &localvar_buffer [index];
int wide = TYPE_IS_WIDE (TREE_TYPE (decl));
int i;
i = info->debug_offset;
if (i >= 0)
{
register unsigned char *ptr;
/* Point to length field of local_variable_table. */
ptr = localvartable.data + i + 2;
i = end_pc - info->start_pc;
PUT2 (i);
}
if (info->decl != decl)
abort ();
info->decl = NULL_TREE;
if (wide)
{
info++;
if (info->decl != TYPE_SECOND)
abort ();
info->decl = NULL_TREE;
}
}
#define STACK_TARGET 1
#define IGNORE_TARGET 2
/* Allocate a new chunk on obstack WORK, and link it in after LAST.
Set the data and size fields to DATA and SIZE, respectively.
However, if DATA is NULL and SIZE>0, allocate a buffer as well. */
struct chunk *
alloc_chunk (last, data, size, work)
struct chunk *last;
unsigned char *data;
int size;
struct obstack *work;
{
struct chunk *chunk = (struct chunk *)
obstack_alloc (work, sizeof(struct chunk));
if (data == NULL && size > 0)
data = obstack_alloc (work, size);
chunk->next = NULL;
chunk->data = data;
chunk->size = size;
last->next = chunk;
return chunk;
}
/* Get the access flags of a class (TYPE_DECL), a method (FUNCTION_DECL), or
a field (FIELD_DECL or VAR_DECL, if static), as encoded in a .class file. */
int
get_access_flags (decl)
tree decl;
{
int flags = 0;
int isfield = TREE_CODE (decl) == FIELD_DECL || TREE_CODE (decl) == VAR_DECL;
if (CLASS_PUBLIC (decl)) /* same as FIELD_PUBLIC and METHOD_PUBLIC */
flags |= ACC_PUBLIC;
if (CLASS_FINAL (decl)) /* same as FIELD_FINAL and METHOD_FINAL */
flags |= ACC_PUBLIC;
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_SUPER (decl))
flags |= ACC_SUPER;
if (CLASS_ABSTRACT (decl))
flags |= ACC_ABSTRACT;
if (CLASS_INTERFACE (decl))
flags |= ACC_INTERFACE;
}
else
fatal ("internal error - bad argument to get_access_flags");
if (TREE_CODE (decl) == FUNCTION_DECL)
{
if (METHOD_NATIVE (decl))
flags |= ACC_NATIVE;
if (METHOD_STATIC (decl))
flags |= ACC_STATIC;
if (METHOD_FINAL (decl))
flags |= ACC_FINAL;
if (METHOD_SYNCHRONIZED (decl))
flags |= ACC_SYNCHRONIZED;
if (METHOD_ABSTRACT (decl))
flags |= ACC_ABSTRACT;
}
if (isfield)
{
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. */
void
write_chunks (stream, chunks)
FILE* stream;
struct chunk *chunks;
{
for (; chunks != NULL; chunks = chunks->next)
fwrite (chunks->data, chunks->size, 1, stream);
}
void
push_constant1 (index)
int index;
{
if (index < 256)
{
OP1 (OPCODE_ldc);
OP1 (index);
}
else
{
OP1 (OPCODE_ldc_w);
OP2 (index);
}
}
void
push_constant2 (index)
int index;
{
RESERVE (3);
OP1 (OPCODE_ldc2_w);
OP2 (index);
}
void
push_int_const (i)
HOST_WIDE_INT i;
{
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 (code_cpool, CONSTANT_Integer, i & 0xFFFFFFFF);
push_constant1 (i);
}
}
void
push_long_const (lo, hi)
HOST_WIDE_INT lo, hi;
{
if (hi == 0 && lo >= 0 && lo <= 1)
{
RESERVE(1);
OP1(OPCODE_lconst_0 + lo);
}
#if 0
else if ((jlong) (jint) i == i)
{
push_int_const ((jint) i);
RESERVE (1);
OP1 (OPCODE_i2l);
}
#endif
else
{
HOST_WIDE_INT w1, w2;
lshift_double (lo, hi, -32, 64, &w1, &w2, 1);
hi = find_constant1 (code_cpool, CONSTANT_Long,
w1 & 0xFFFFFFFF, lo & 0xFFFFFFFF);
push_constant2 (hi);
}
}
void
field_op (field, opcode)
tree field;
int opcode;
{
int index = find_fieldref_index (code_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. */
int
adjust_typed_op (type)
tree type;
{
switch (TREE_CODE (type))
{
case BOOLEAN_TYPE: return 5;
case CHAR_TYPE: return 6;
case POINTER_TYPE:
case RECORD_TYPE: return 4;
case INTEGER_TYPE:
switch (TYPE_PRECISION (type))
{
case 8: return 5;
case 16: return 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;
}
abort ();
}
void
maybe_wide (opcode, index)
int opcode, index;
{
if (index >= 256)
{
RESERVE (4);
OP1 (196); /* wide */
OP1 (opcode);
OP2 (index);
}
else
{
RESERVE (2);
OP1 (opcode);
OP1 (index);
}
}
#define PC BUFFER_LENGTH(&bytecode)
/* Generate byetcode for sub-expression EXP of METHOD.
TARGET is one of STACK_TARGET or IGNORE_TARGET. */
void
generate_bytecode_insns (method, exp, target)
tree method;
tree exp;
int target;
{
rtx value;
tree type = TREE_TYPE (exp);
enum java_opcode jopcode;
int op;
switch (TREE_CODE (exp))
{
case BLOCK:
if (BLOCK_EXPR_BODY (exp))
{
tree local;
for (local = BLOCK_EXPR_DECLS (exp); local; )
{
tree next = TREE_CHAIN (local);
localvar_alloc (local, PC);
local = next;
}
generate_bytecode_insns (method, BLOCK_EXPR_BODY (exp), target);
for (local = BLOCK_EXPR_DECLS (exp); local; )
{
tree next = TREE_CHAIN (local);
localvar_free (local, PC);
local = next;
}
}
break;
case COMPOUND_EXPR:
generate_bytecode_insns (method, TREE_OPERAND (exp, 0), IGNORE_TARGET);
generate_bytecode_insns (method, TREE_OPERAND (exp, 1), target);
break;
case EXPR_WITH_FILE_LOCATION:
{
char *saved_input_filename = input_filename;
int saved_lineno = lineno;
input_filename = EXPR_WFL_FILENAME (exp);
lineno = EXPR_WFL_LINENO (exp);
if (EXPR_WFL_EMIT_LINE_NOTE (exp))
put_linenumber (PC, EXPR_WFL_LINENO (exp));
generate_bytecode_insns (method, EXPR_WFL_NODE (exp), target);
input_filename = saved_input_filename;
lineno = saved_lineno;
}
break;
case INTEGER_CST:
if (target == IGNORE_TARGET) ; /* do nothing */
else if (TREE_CODE (type) == POINTER_TYPE)
{
if (! integer_zerop (exp))
abort();
RESERVE(1);
OP1 (OPCODE_aconst_null);
NOTE_PUSH (1);
}
else if (TYPE_PRECISION (type) <= 32)
{
push_int_const (TREE_INT_CST_LOW (exp));
NOTE_PUSH (1);
}
else
{
push_long_const (TREE_INT_CST_LOW (exp), TREE_INT_CST_HIGH (exp));
NOTE_PUSH (2);
}
break;
case VAR_DECL:
if (TREE_STATIC (exp))
{
field_op (exp, OPCODE_getstatic);
break;
}
/* ... fall through ... */
case PARM_DECL:
{
int kind = adjust_typed_op (type);
int index = DECL_LOCAL_INDEX (exp);
if (index <= 3)
{
RESERVE (1);
OP1 (26 + 4 * kind + index); /* [ilfda]load_[0123] */
}
else
maybe_wide (21 + kind, index); /* [ilfda]load */
}
break;
case INDIRECT_REF:
generate_bytecode_insns (method, TREE_OPERAND (exp, 0), target);
break;
case ARRAY_REF:
generate_bytecode_insns (method, TREE_OPERAND (exp, 0), target);
generate_bytecode_insns (method, TREE_OPERAND (exp, 1), target);
if (target != IGNORE_TARGET)
{
jopcode = OPCODE_iaload + adjust_typed_op (type);
RESERVE(1);
OP1 (jopcode);
}
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 (method, obj,
is_static ? IGNORE_TARGET : target);
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);
}
}
break;
case RETURN_EXPR:
if (!TREE_OPERAND (exp, 0))
op = OPCODE_return;
else
{
exp = TREE_OPERAND (exp, 0);
if (TREE_CODE (exp) != MODIFY_EXPR)
abort ();
exp = TREE_OPERAND (exp, 1);
op = OPCODE_ireturn + adjust_typed_op (TREE_TYPE (exp));
generate_bytecode_insns (method, exp, STACK_TARGET);
}
RESERVE (1);
OP1 (op);
break;
case MODIFY_EXPR:
{
tree lhs = TREE_OPERAND (exp, 0);
tree rhs = TREE_OPERAND (exp, 1);
HOST_WIDE_INT value;
#if 0
if (TREE_CODE (rhs) == PLUS_EXPR
&& TREE_CODE (lhs) == VAR_DECL
/* && FIXME lhs is a local variable */
&& TYPE_MODE (TREE)TYPE (lhs) == SImode /* ??? */
&& TREE_OPERAND (rhs, 0) == lhs
&& TREE_CODE (TREE_OPERAND (rhs, 1)) == INTEGER_CST
/* or vice versa FIXME */
&& (value = TREE_INT_CST_LOW (TREE_OPERAND (rhs, 1)),
(value >= -32768 && value <= 32767)))
{
emit_insn (gen_rtx (SET, SImode,
DECL_RTL (lhs),
gen_rtx (PLUS, SImode,
DECL_RTL (lhs),
gen_rtx_CONST_INT (SImode, value))));
return DECL_RTL (lhs);
}
#endif
if (TREE_CODE (lhs) == COMPONENT_REF)
generate_bytecode_insns (method, TREE_OPERAND (lhs, 0), STACK_TARGET);
else if (TREE_CODE (lhs) == ARRAY_REF)
{
generate_bytecode_insns (method,
TREE_OPERAND (lhs, 0), STACK_TARGET);
generate_bytecode_insns (method,
TREE_OPERAND (lhs, 1), STACK_TARGET);
}
generate_bytecode_insns (method, rhs, STACK_TARGET);
if (target != IGNORE_TARGET)
{
RESERVE (1);
OP1 (TYPE_IS_WIDE (type) ? OPCODE_dup2_x1 : OPCODE_dup_x1);
}
if (TREE_CODE (lhs) == COMPONENT_REF)
{
tree field = TREE_OPERAND (lhs, 1);
field_op (field,
FIELD_STATIC (field) ? OPCODE_putstatic
: OPCODE_putfield);
}
else if (TREE_CODE (lhs) == VAR_DECL
|| TREE_CODE (lhs) == PARM_DECL)
{
if (FIELD_STATIC (lhs))
{
field_op (lhs, OPCODE_putstatic);
}
else
{
int index = DECL_LOCAL_INDEX (lhs);
int opcode = adjust_typed_op (TREE_TYPE (lhs));
if (index <= 3)
{
RESERVE (1);
opcode = 59 + 4 * opcode + index;
OP1 (opcode); /* [ilfda]store_[0123] */
}
else
{
maybe_wide (54 + opcode, index); /* [ilfda]store */
}
}
}
else if (TREE_CODE (lhs) == ARRAY_REF)
{
jopcode = OPCODE_iastore + adjust_typed_op (TREE_TYPE (lhs));
RESERVE(1);
OP1 (jopcode);
}
else
fatal ("internal error (bad lhs to MODIFY_EXPR)");
}
break;
case PLUS_EXPR:
jopcode = OPCODE_iadd + adjust_typed_op (type);
goto binop;
case MINUS_EXPR:
jopcode = OPCODE_isub + adjust_typed_op (type);
goto binop;
case MULT_EXPR:
jopcode = OPCODE_imul + adjust_typed_op (type);
goto binop;
case TRUNC_DIV_EXPR:
case RDIV_EXPR:
jopcode = OPCODE_idiv + adjust_typed_op (type);
goto binop;
binop:
generate_bytecode_insns (method, TREE_OPERAND (exp, 0), target);
generate_bytecode_insns (method, TREE_OPERAND (exp, 1), target);
if (target == STACK_TARGET)
{
RESERVE(1);
OP1 (jopcode);
}
break;
case CALL_EXPR:
{
tree t;
for (t = TREE_OPERAND (exp, 1); t != NULL_TREE; t = TREE_CHAIN (t))
{
generate_bytecode_insns (method, TREE_VALUE (t), STACK_TARGET);
}
t = TREE_OPERAND (exp, 0);
if (TREE_CODE (t) == FUNCTION_DECL)
{
int index = find_methodref_index (code_cpool, t);
RESERVE (3);
if (DECL_CONSTRUCTOR_P (t))
OP1 (OPCODE_invokespecial);
else if (METHOD_STATIC (t))
OP1 (OPCODE_invokestatic);
else
OP1 (OPCODE_invokevirtual);
OP2 (index);
break;
}
}
/* fall through */
default:
error("internal error - tree code not implemented: ", TREE_CODE (exp));
}
}
/* Generate and return a list of chunks containing the class CLAS
in the .class file representation. The list can be written to a
.class file using write_chunks. Allocate chunks from obstack WORK. */
/* Currently does not write any attributes i.e. no code. */
struct chunk *
generate_classfile (clas, work)
tree clas;
struct obstack *work;
{
CPool cpool;
struct chunk head;
struct chunk *chunk;
struct chunk *cpool_chunk;
char *ptr;
int i;
char *fields_count_ptr;
int fields_count = 0;
char *methods_count_ptr;
int methods_count = 0;
tree part;
int total_supers
= clas == object_type_node ? 0
: TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (clas));
chunk = alloc_chunk (&head, NULL, 8, work);
ptr = chunk->data;
PUT4 (0xCafeBabe); /* Magic number */
PUT2 (3); /* Minor version */
PUT2 (45); /* Major version */
CPOOL_INIT(&cpool);
cpool_chunk = chunk = alloc_chunk (chunk, NULL, 0, work);
/* Next allocate the chunk containing acces_flags through fields_counr. */
if (clas == object_type_node)
i = 10;
else
i = 8 + 2 * total_supers;
chunk = alloc_chunk (chunk, NULL, i, work);
ptr = chunk->data;
i = get_access_flags (TYPE_NAME (clas)); PUT2 (i); /* acces_flags */
i = find_class_constant (&cpool, clas); PUT2 (i); /* this_class */
if (clas == object_type_node)
{
PUT2(0); /* super_class */
PUT2(0); /* interfaces_count */
}
else
{
tree basetypes = TYPE_BINFO_BASETYPES (clas);
tree base = BINFO_TYPE (TREE_VEC_ELT (basetypes, 0));
int j = find_class_constant (&cpool, base); PUT2 (j); /* super_class */
PUT2 (total_supers - 1); /* interfaces_count */
for (i = 1; i < total_supers; i++)
{
base = BINFO_TYPE (TREE_VEC_ELT (basetypes, i));
j = find_class_constant (&cpool, base);
PUT2 (j);
}
}
fields_count_ptr = ptr;
for (part = TYPE_FIELDS (clas); part; part = TREE_CHAIN (part))
{
if (DECL_NAME (part) == NULL_TREE)
continue;
chunk = alloc_chunk (chunk, NULL, 8, work);
ptr = chunk->data;
i = get_access_flags (part); PUT2 (i);
i = find_utf8_constant (&cpool, DECL_NAME (part)); PUT2 (i);
i = find_utf8_constant (&cpool, build_java_signature (TREE_TYPE (part)));
PUT2(i);
PUT2 (0); /* attributes_count */
/* FIXME - emit ConstantValue attribute when appropriate */
fields_count++;
}
ptr = fields_count_ptr; PUT2 (fields_count);
chunk = alloc_chunk (chunk, NULL, 2, work);
ptr = methods_count_ptr = chunk->data;
PUT2 (0);
for (part = TYPE_METHODS (clas); part; part = TREE_CHAIN (part))
{
tree body = BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (part));
int linenumber_size; /* 4 * number of line number entries */
chunk = alloc_chunk (chunk, NULL, 8, work);
ptr = chunk->data;
i = get_access_flags (part); PUT2 (i);
i = find_utf8_constant (&cpool, DECL_NAME (part)); PUT2 (i);
i = find_utf8_constant (&cpool, build_java_signature (TREE_TYPE (part)));
PUT2 (i);
PUT2 (body != NULL_TREE ? 1 : 0); /* attributes_count */
if (body != NULL_TREE)
{
int code_attributes_count = 0;
int linenumber_size; /* 4 * number of line number entries */
int localvartable_size; /* 10 * number of local variable entries */
static tree Code_node = NULL_TREE;
tree t;
char *attr_len_ptr;
int code_length;
if (Code_node == NULL_TREE)
Code_node = get_identifier ("Code");
chunk = alloc_chunk (chunk, NULL, 14, work);
ptr = chunk->data;
i = find_utf8_constant (&cpool, Code_node); PUT2 (i);
attr_len_ptr = ptr;
BUFFER_RESET (&bytecode);
BUFFER_RESET (&localvartable);
BUFFER_RESET (&linenumbers);
BUFFER_RESET (&localvars);
code_SP = 0;
code_SP_max = 0;
code_cpool = &cpool;
for (t = DECL_ARGUMENTS (part); t != NULL_TREE; t = TREE_CHAIN (t))
localvar_alloc (t, 0);
generate_bytecode_insns (part, body, IGNORE_TARGET);
code_length = PC;
for (t = DECL_ARGUMENTS (part); t != NULL_TREE; t = TREE_CHAIN (t))
localvar_free (t, code_length);
linenumber_size = BUFFER_LENGTH (&linenumbers);
localvartable_size = BUFFER_LENGTH (&localvartable);
chunk = alloc_chunk (chunk, NULL, code_length, work);
bcopy (bytecode.data, chunk->data, code_length);
ptr = attr_len_ptr;
i = 8 + code_length + 4;
if (linenumber_size > 0)
{
code_attributes_count++;
i += 8 + linenumber_size;
}
if (localvartable_size > 0)
{
code_attributes_count++;
i += 8 + localvartable_size;
}
PUT4 (i); /* attribute_length */
PUT2 (code_SP_max); /* max_stack */
PUT2 (localvar_max); /* max_locals */
PUT4 (code_length);
chunk = alloc_chunk (chunk, NULL, 4, work);
ptr = chunk->data;
PUT2 (0); /* exception_table_length */
PUT2 (code_attributes_count);
/* Write the LineNumberTable attribute. */
if (linenumber_size > 0)
{
static tree LineNumberTable_node = NULL_TREE;
chunk = alloc_chunk (chunk, NULL, 8 + linenumber_size, work);
ptr = chunk->data;
if (LineNumberTable_node == NULL_TREE)
LineNumberTable_node = get_identifier ("LineNumberTable");
i = find_utf8_constant (&cpool, LineNumberTable_node);
PUT2 (i); /* attribute_name_index */
i = 2 + linenumber_size; PUT4 (i); /* attribute_length */
i = linenumber_size >> 2; PUT2 (i);
PUTN (linenumbers.data, linenumber_size);
}
/* Write the LocalVariableTable attribute. */
if (localvartable_size > 0)
{
static tree LocalVariableTable_node = NULL_TREE;
chunk = alloc_chunk (chunk, NULL, 8 + localvartable_size, work);
ptr = chunk->data;
if (LocalVariableTable_node == NULL_TREE)
LocalVariableTable_node = get_identifier("LocalVariableTable");
i = find_utf8_constant (&cpool, LocalVariableTable_node);
PUT2 (i); /* attribute_name_index */
i = 2 + localvartable_size; PUT4 (i); /* attribute_length */
i = localvartable_size / 10; PUT2 (i);
PUTN (localvartable.data, localvartable_size);
}
}
methods_count++;
}
ptr = methods_count_ptr; PUT2 (methods_count);
chunk = alloc_chunk (chunk, NULL, 2, work);
ptr = chunk->data;
PUT2 (0); /* attributes_count */
/* New finally generate the contents of the constant pool chunk. */
i = count_constant_pool_bytes (&cpool);
ptr = obstack_alloc (work, i);
cpool_chunk->data = ptr;
cpool_chunk->size = i;
write_constant_pool (&cpool, ptr, i);
CPOOL_FINISH (&cpool);
return head.next;
}
char*
make_class_file_name (clas)
tree clas;
{
/* Should prepend an output directly, but need an option to specify it. */
return IDENTIFIER_POINTER (identifier_subst (DECL_NAME (TYPE_NAME (clas)),
"", '.', '/', ".class"));
}
/* Write out the contens of a class (RECORD_TYPE) CLAS, as a .class file.
The output .class file name is make_class_file_name(CLAS). */
void
write_classfile (clas)
tree clas;
{
struct obstack *work = &temporary_obstack;
char *class_file_name = make_class_file_name (clas);
struct chunk *chunks;
FILE* stream = fopen (class_file_name, "wb");
if (stream == NULL)
fatal ("failed to open `%s' for writing", class_file_name);
chunks = generate_classfile (clas, work);
write_chunks (stream, chunks);
if (fclose (stream))
fatal ("failed to close after writing `%s'", class_file_name);
obstack_free (work, chunks);
}

260
gcc/java/jcf.h Normal file
View file

@ -0,0 +1,260 @@
/* Utility macros to read Java(TM) .class files and byte codes.
Copyright (C) 1996 Free Software Foundation, Inc.
This program 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.
This program 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, 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. */
/* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
#ifndef JCF_H
#define JCF_H
#include "javaop.h"
#ifndef DEFUN
#if defined (__STDC__)
#define AND ,
#define PTR void *
#define DEFUN(name, arglist, args) name(args)
#else
#define PTR char *
#define AND ;
#define DEFUN(name, arglist, args) name arglist args;
#define inline static
#endif
#endif /* !DEFUN */
#ifndef PROTO
#if defined (__STDC__)
#define PROTO(paramlist) paramlist
#else
#define PROTO(paramlist) ()
#endif
#endif
#ifndef JCF_u4
#define JCF_u4 unsigned long
#endif
#ifndef JCF_u2
#define JCF_u2 unsigned short
#endif
#define ALLOC (void*)malloc
#define REALLOC (void*)realloc
#ifndef FREE
#define FREE(PTR) free(PTR)
#endif
#ifdef JCF_word
#define JCF_word JCF_u4
#endif
#define JCF_ZIP 1
#define JCF_CLASS 2
#define JCF_SOURCE 3
struct JCF;
typedef int (*jcf_filbuf_t) PROTO ((struct JCF*, int needed));
typedef struct CPool {
/* Available number of elements in the constants array, before it
must be re-allocated. */
int capacity;
/* The constant_pool_count. */
int count;
uint8* tags;
jword* data;
} CPool;
/* JCF encapsulates the state of reading a Java Class File. */
typedef struct JCF {
unsigned char *buffer;
unsigned char *buffer_end;
unsigned char *read_ptr;
unsigned char *read_end;
int seen_in_zip;
int java_source;
int outofsynch; /* Found a class file out of synch
with the matching source file. */
long zip_offset;
jcf_filbuf_t filbuf;
void *read_state;
char *filename;
char *classname;
void *zipd; /* Directory entry where it was found */
JCF_u2 access_flags, this_class, super_class;
CPool cpool;
} JCF;
/*typedef JCF* JCF_FILE;*/
/* The CPOOL macros take a (pointer to a) CPool.
The JPOOL macros take a (pointer to a) JCF.
Some of the latter should perhaps be deprecated or removed. */
#define CPOOL_COUNT(CPOOL) ((CPOOL)->count)
#define JPOOL_SIZE(JCF) CPOOL_COUNT(&(JCF)->cpool)
#define JPOOL_TAG(JCF, INDEX) ((JCF)->cpool.tags[INDEX])
/* The INDEX'th constant pool entry as a JCF_u4. */
#define CPOOL_UINT(CPOOL, INDEX) ((CPOOL)->data[INDEX])
#define JPOOL_UINT(JCF, INDEX) CPOOL_UINT(&(JCF)->cpool, INDEX) /*deprecated*/
/* The first uint16 of the INDEX'th constant pool entry. */
#define CPOOL_USHORT1(CPOOL, INDEX) ((CPOOL)->data[INDEX] & 0xFFFF)
#define JPOOL_USHORT1(JCF, INDEX) CPOOL_USHORT1(&(JCF)->cpool, INDEX)
/* The second uint16 of the INDEX'th constant pool entry. */
#define CPOOL_USHORT2(CPOOL, INDEX) ((CPOOL)->data[INDEX] >> 16)
#define JPOOL_USHORT2(JCF, INDEX) CPOOL_USHORT2(&(JCF)->cpool, INDEX)
#define JPOOL_LONG(JCF, INDEX) \
WORDS_TO_LONG (JPOOL_UINT(JCF, INDEX), JPOOL_UINT(JCF, (INDEX)+1))
#define JPOOL_DOUBLE(JCF, INDEX) \
WORDS_TO_DOUBLE (JPOOL_UINT(JCF, INDEX), JPOOL_UINT(JCF, (INDEX)+1))
#ifndef JPOOL_UTF_LENGTH
#define JPOOL_UTF_LENGTH(JCF, INDEX) \
GET_u2 ((JCF)->buffer+JPOOL_UINT(JCF, INDEX))
#endif
#ifndef JPOOL_UTF_DATA
#define JPOOL_UTF_DATA(JCF, INDEX) \
((JCF)->buffer+JPOOL_UINT(JCF, INDEX)+2)
#endif
#define JPOOL_INT(JCF, INDEX) ((jint) JPOOL_UINT (JCF, INDEX))
#define JPOOL_FLOAT(JCF, INDEX) WORD_TO_FLOAT (JPOOL_UINT (JCF, INDEX))
#define CPOOL_INDEX_IN_RANGE(CPOOL, INDEX) \
((INDEX) > 0 && (INDEX) < CPOOL_COUNT(CPOOL))
#define CPOOL_FINISH(CPOOL) { \
if ((CPOOL)->tags) FREE ((CPOOL)->tags); \
if ((CPOOL)->data) FREE ((CPOOL)->data); }
#define JCF_FINISH(JCF) { \
CPOOL_FINISH(&(JCF)->cpool); \
if ((JCF)->buffer) FREE ((JCF)->buffer); \
if ((JCF)->filename) FREE ((JCF)->filename); \
if ((JCF)->classname) FREE ((JCF)->classname); }
#define CPOOL_INIT(CPOOL) \
((CPOOL)->capacity = 0, (CPOOL)->count = 0, (CPOOL)->tags = 0, (CPOOL)->data = 0)
#define CPOOL_REINIT(CPOOL) ((CPOOL)->count = 0)
#define JCF_ZERO(JCF) \
((JCF)->buffer = (JCF)->buffer_end = (JCF)->read_ptr = (JCF)->read_end = 0,\
(JCF)->read_state = 0, (JCF)->filename = (JCF)->classname = 0, \
CPOOL_INIT(&(JCF)->cpool), (JCF)->java_source = 0)
/* Given that PTR points to a 2-byte unsigned integer in network
(big-endian) byte-order, return that integer. */
#define GET_u2(PTR) (((PTR)[0] << 8) | ((PTR)[1]))
/* Like GET_u2, but for little-endian format. */
#define GET_u2_le(PTR) (((PTR)[1] << 8) | ((PTR)[0]))
/* Given that PTR points to a 4-byte unsigned integer in network
(big-endian) byte-order, return that integer. */
#define GET_u4(PTR) (((JCF_u4)(PTR)[0] << 24) | ((JCF_u4)(PTR)[1] << 16) \
| ((JCF_u4)(PTR)[2] << 8) | ((JCF_u4)(PTR)[3]))
/* Like GET_u4, but for little-endian order. */
#define GET_u4_le(PTR) (((JCF_u4)(PTR)[3] << 24) | ((JCF_u4)(PTR)[2] << 16) \
| ((JCF_u4)(PTR)[1] << 8) | ((JCF_u4)(PTR)[0]))
/* Make sure there are COUNT bytes readable. */
#define JCF_FILL(JCF, COUNT) \
((JCF)->read_end-(JCF)->read_ptr >= (COUNT) ? 0 : (*(JCF)->filbuf)(JCF, COUNT))
#define JCF_GETC(JCF) (JCF_FILL(JCF, 1) ? -1 : *(JCF)->read_ptr++)
#define JCF_READ(JCF, BUFFER, N) \
(memcpy (BUFFER, (JCF)->read_ptr, N), (JCF)->read_ptr += (N))
#define JCF_SKIP(JCF,N) ((JCF)->read_ptr += (N))
#define JCF_readu(JCF) (*(JCF)->read_ptr++)
/* Reads an unsigned 2-byte integer in network (big-endian) byte-order
from JCF. Returns that integer.
Does not check for EOF (make sure to call JCF_FILL before-hand). */
#define JCF_readu2(JCF) ((JCF)->read_ptr += 2, GET_u2 ((JCF)->read_ptr-2))
#define JCF_readu2_le(JCF) ((JCF)->read_ptr += 2, GET_u2_le((JCF)->read_ptr-2))
/* Like JCF_readu2, but read a 4-byte unsigned integer. */
#define JCF_readu4(JCF) ((JCF)->read_ptr += 4, GET_u4 ((JCF)->read_ptr-4))
#define JCF_readu4_le(JCF) ((JCF)->read_ptr += 4, GET_u4_le((JCF)->read_ptr-4))
#define JCF_TELL(JCF) ((JCF)->read_ptr - (JCF)->buffer)
#define JCF_SEEK(JCF, POS) ((JCF)->read_ptr = (JCF)->buffer + (POS))
#define ACC_PUBLIC 0x0001
#define ACC_PRIVATE 0x0002
#define ACC_PROTECTED 0x0004
#define ACC_STATIC 0x0008
#define ACC_FINAL 0x0010
#define ACC_SYNCHRONIZED 0x0020
#define ACC_SUPER 0x0020
#define ACC_VOLATILE 0x0040
#define ACC_TRANSIENT 0x0080
#define ACC_NATIVE 0x0100
#define ACC_INTERFACE 0x0200
#define ACC_ABSTRACT 0x0400
#define CONSTANT_Class 7
#define CONSTANT_Fieldref 9
#define CONSTANT_Methodref 10
#define CONSTANT_InterfaceMethodref 11
#define CONSTANT_String 8
#define CONSTANT_Integer 3
#define CONSTANT_Float 4
#define CONSTANT_Long 5
#define CONSTANT_Double 6
#define CONSTANT_NameAndType 12
#define CONSTANT_Utf8 1
#define CONSTANT_Unicode 2
extern char *classpath;
#define DEFAULT_CLASS_PATH "."
extern char *find_class PROTO ((const char *, int, JCF*, int));
extern char *find_classfile PROTO ((char *, JCF*));
extern int jcf_filbuf_from_stdio PROTO ((JCF *jcf, int count));
extern void jcf_out_of_synch PROTO((JCF *));
extern int jcf_unexpected_eof PROTO ((JCF*, int));
/* Extract a character from a Java-style Utf8 string.
* PTR points to the current character.
* LIMIT points to the end of the Utf8 string.
* PTR is incremented to point after the character thta gets returns.
* On an error, -1 is returned. */
#define UTF8_GET(PTR, LIMIT) \
((PTR) >= (LIMIT) ? -1 \
: *(PTR) < 128 ? *(PTR)++ \
: (*(PTR)&0xE0) == 0xC0 && ((PTR)+=2)<=(LIMIT) && ((PTR)[-1]&0xC0) == 0x80 \
? (((PTR)[-2] & 0x1F) << 6) + ((PTR)[-1] & 0x3F) \
: (*(PTR) & 0xF0) == 0xE0 && ((PTR) += 3) <= (LIMIT) \
&& ((PTR)[-2] & 0xC0) == 0x80 && ((PTR)[-1] & 0xC0) == 0x80 \
? (((PTR)[-3]&0x1F) << 12) + (((PTR)[-2]&0x3F) << 6) + ((PTR)[-1]&0x3F) \
: ((PTR)++, -1))
/* Debug macros, for the front end */
extern int quiet_flag;
#ifdef SOURCE_FRONTEND_DEBUG
#undef SOURCE_FRONTEND_DEBUG
#define SOURCE_FRONTEND_DEBUG(X) \
{if (!quiet_flag) {printf ("* "); printf X; putchar ('\n');} }
#else
#define SOURCE_FRONTEND_DEBUG(X)
#endif
#endif

235
gcc/java/jv-scan.c Normal file
View file

@ -0,0 +1,235 @@
/* Main for jv-scan
Copyright (C) 1998 Free Software Foundation, Inc.
Contributed by Alexandre Petit-Bianco (apbianco@cygnus.com)
This file is part of GNU CC.
GNU CC 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.
GNU CC 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include <stdio.h>
#include <stdlib.h>
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include "gansidecl.h" /* Definitions of PROTO and VPROTO */
#include "obstack.h" /* We use obstacks in lex.c */
void fatal VPROTO((char *s, ...));
void warning VPROTO((char *s, ...));
void gcc_obstack_init PROTO ((struct obstack *obstack));
extern void reset_report PROTO ((void));
#define JC1_LITE
#include "parse.h"
/* Current input file and output file IO streams. */
FILE *finput, *out;
/* Current input filename. */
char *input_filename;
/* Executable name. */
char *exec_name;
/* Flags matching command line options. */
int flag_find_main = 0;
int flag_dump_class = 0;
int flag_list_filename = 0;
/* jc1-lite main entry point */
int
main (argc, argv, envp)
int argc;
char **argv;
char **envp;
{
int i = 1;
char *output_file = NULL;
long ft;
exec_name = argv[0];
/* Default for output */
out = stdout;
/* Process options first */
while (argv [i])
{
if (argv [i][0] == '-')
{
/* Dump result into a file */
if (!strcmp (argv [i], "-o") && i+1 < argc)
{
argv [i] = NULL;
output_file = argv [++i];
argv [i] = NULL;
}
/* Print the name of the class that contains main */
else if (!strcmp (argv [i], "--print-main"))
flag_find_main = 1;
else if (!strcmp (argv [i], "--list-filename"))
flag_list_filename = 1;
/* List all the classes found in a source file */
else if (!strcmp (argv [i], "--list-class"))
flag_dump_class = 1;
else
warning ("Unrecognized argument `%s'", argv[i]);
/* non recognized argument ignored silently */
argv [i] = NULL; /* Nullify so it's not considered a file */
}
i++;
}
/* No flags? Do nothing */
if (!flag_find_main && !flag_dump_class)
exit (0);
/* Check on bad usage */
if (flag_find_main && flag_dump_class)
fatal ("Options `--print-main' and `--list-class' can't be turned on "
"at the same time", argv [0]);
if (output_file && !(out = fopen (output_file, "w")))
fatal ("Can't open output file `%s'", argv [0], output_file);
ft = ftell (out);
gcc_obstack_init (&temporary_obstack);
java_push_parser_context ();
for ( i = 1; i < argc; i++ )
if (argv [i])
{
input_filename = argv [i];
if ( (finput = fopen (argv [i], "r")) )
{
java_init_lex ();
yyparse ();
if (ftell (out) != ft)
fputc ('\n', out);
ft = ftell (out);
fclose (finput);
reset_report ();
}
else
fatal ("File not found `%s'", argv [0], argv [i]);
}
/* Flush and close */
if (ftell (out) != ft)
fputc ('\n', out);
if (!output_file)
fclose (out);
exit (0);
}
/* Error report, memory, obstack initialization and other utility
functions */
void
fatal VPROTO((char *s, ...))
{
#ifndef __STDC__
char *s;
#endif
va_list ap;
VA_START (ap, s);
#ifndef __STDC__
s = va_arg (ap, char *);
#endif
fprintf (stderr, "%s: error: ", exec_name);
vfprintf (stderr, s, ap);
fputc ('\n', stderr);
va_end (ap);
exit (1);
}
char *
xmalloc (size)
unsigned size;
{
register char *value;
if (size == 0)
size = 1;
value = (char *) malloc (size);
if (value == 0)
fatal ("virtual memory exhausted");
return value;
}
char *
xstrdup (string)
char *string;
{
int length = strlen (string)+1;
char *to_return = xmalloc (length);
strcpy (to_return, string);
return to_return;
}
void
warning VPROTO((char *s, ...))
{
#ifndef __STDC__
char *s;
#endif
va_list ap;
VA_START (ap, s);
#ifndef __STDC__
s = va_arg (ap, char *);
#endif
fprintf (stderr, "%s: warning: ", exec_name);
vfprintf (stderr, s, ap);
fputc ('\n', stderr);
va_end (ap);
}
void
gcc_obstack_init (obstack)
struct obstack *obstack;
{
/* Let particular systems override the size of a chunk. */
#ifndef OBSTACK_CHUNK_SIZE
#define OBSTACK_CHUNK_SIZE 0
#endif
/* Let them override the alloc and free routines too. */
#ifndef OBSTACK_CHUNK_ALLOC
#define OBSTACK_CHUNK_ALLOC xmalloc
#endif
#ifndef OBSTACK_CHUNK_FREE
#define OBSTACK_CHUNK_FREE free
#endif
_obstack_begin (obstack, OBSTACK_CHUNK_SIZE, 0,
(void *(*) ()) OBSTACK_CHUNK_ALLOC,
(void (*) ()) OBSTACK_CHUNK_FREE);
}

124
gcc/java/jvgenmain.c Normal file
View file

@ -0,0 +1,124 @@
/* Program to generate "main" a Java(TM) class containing a main method.
Copyright (C) 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC 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.
GNU CC 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, 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. */
/* Written by Per Bothner <bothner@cygnus.com> */
#include <stdio.h>
#include <stdlib.h>
#include "config.h"
#include "obstack.h"
const char main_method_prefix[] = "main__";
const char main_method_suffix[] = "Pt6JArray1ZPQ34java4lang6String";
const char class_mangling_prefix[] = "_CL_";
struct obstack name_obstack;
void
error (const char *str)
{
fprintf (stderr, "%s\n", str);
exit (-1);
}
void *
xmalloc (size)
size_t size;
{
void *ptr = malloc (size);
if (ptr == NULL)
{
fprintf (stderr, "Not enough memory!\n");
exit (-1);
}
return ptr;
}
void
gcc_obstack_init (obstack)
struct obstack *obstack;
{
/* Let particular systems override the size of a chunk. */
#ifndef OBSTACK_CHUNK_SIZE
#define OBSTACK_CHUNK_SIZE 0
#endif
/* Let them override the alloc and free routines too. */
#ifndef OBSTACK_CHUNK_ALLOC
#define OBSTACK_CHUNK_ALLOC xmalloc
#endif
#ifndef OBSTACK_CHUNK_FREE
#define OBSTACK_CHUNK_FREE free
#endif
_obstack_begin (obstack, OBSTACK_CHUNK_SIZE, 0,
(void *(*) ()) OBSTACK_CHUNK_ALLOC,
(void (*) ()) OBSTACK_CHUNK_FREE);
}
int
main (int argc, const char **argv)
{
const char *classname;
FILE *stream;
char *mangled_classname;
if (argc < 2 || argc > 3)
{
fprintf (stderr, "Usage: %s CLASSNAME [OUTFILE]\n", argv[0]);
exit(-1);
}
classname = argv[1];
gcc_obstack_init (&name_obstack);
append_gpp_mangled_classtype (&name_obstack, classname);
mangled_classname = obstack_finish (&name_obstack);
if (argc > 2 && strcmp (argv[2], "-") != 0)
{
const char *outfile = argv[2];
stream = fopen (outfile, "w");
if (stream == NULL)
{
fprintf (stderr, "%s: Cannot open output file: %s\n",
argv[0], outfile);
exit (-1);
}
}
else
stream = stdout;
fprintf (stream, "extern struct Class %s%s;\n",
class_mangling_prefix, mangled_classname);
fprintf (stream, "int main (int argc, const char **argv)\n");
fprintf (stream, "{\n");
fprintf (stream, " JvRunMain (&%s%s, argc, argv);\n",
class_mangling_prefix, mangled_classname);
fprintf (stream, "}\n");
if (stream != stdout && fclose (stream) != 0)
{
fprintf (stderr, "%s: Failed to close output file %s\n",
argv[0], argv[2]);
exit (-1);
}
return 0;
}

357
gcc/java/jvspec.c Normal file
View file

@ -0,0 +1,357 @@
/* Specific flags and argument handling of the front-end of the
GNU compiler for the Java(TM) language.
Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC 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.
GNU CC 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, 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 "gansidecl.h"
#if defined (WITH_THREAD_posix) || defined (WITH_THREAD_pthreads)
#define THREAD_NAME "-lpthread"
#elif defined (WITH_THREAD_qt)
#define THREAD_NAME "-lqthreads"
#endif
/* This bit is set if we saw a `-xfoo' language specification. */
#define LANGSPEC (1<<1)
/* This bit is set if they did `-lm' or `-lmath'. */
#define MATHLIB (1<<2)
/* This bit is set if they did `-lc'. */
#define WITHLIBC (1<<3)
/* This bit is set if they did `-lgc'. */
#define GCLIB (1<<4)
/* This bit is set if they did `-lpthread' (or added some other thread
library). */
#define THREADLIB (1<<5)
#ifndef MATH_LIBRARY
#define MATH_LIBRARY "-lm"
#endif
extern char *xmalloc PROTO((size_t));
extern int do_spec PROTO((char *));
extern char *input_filename;
extern size_t input_filename_length;
char *main_class_name = NULL;
int lang_specific_extra_outfiles = 0;
char jvgenmain_spec[] =
"jvgenmain %i %{!pipe:%g.i} |\n\
cc1 %{!pipe:%g.i} %1 \
%{!Q:-quiet} -dumpbase %b.c %{d*} %{m*} %{a*}\
%{g*} %{O*} \
%{v:-version} %{pg:-p} %{p} %{f*}\
%{aux-info*}\
%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
%{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
%{!S:as %a %Y -o %w%b%O %{!pipe:%g.s} %A\n }";
void
lang_specific_driver (fn, in_argc, in_argv, in_added_libraries)
void (*fn)();
int *in_argc;
char ***in_argv;
int *in_added_libraries;
{
int i, j;
/* If non-zero, the user gave us the `-v' flag. */
int saw_verbose_flag = 0;
/* This will be 0 if we encounter a situation where we should not
link in libjava. */
int library = 1;
/* The number of arguments being added to what's in argv, other than
libraries. We use this to track the number of times we've inserted
-xc++/-xnone. */
int added = 2;
/* Used to track options that take arguments, so we don't go wrapping
those with -xc++/-xnone. */
char *quote = NULL;
/* The new argument list will be contained in this. */
char **arglist;
/* Non-zero if we saw a `-xfoo' language specification on the
command line. Used to avoid adding our own -xc++ if the user
already gave a language for the file. */
int saw_speclang = 0;
/* "-lm" or "-lmath" if it appears on the command line. */
char *saw_math = 0;
/* "-lc" if it appears on the command line. */
char *saw_libc = 0;
/* "-lgc" if it appears on the command line. */
char *saw_gc = 0;
/* Saw `-l' option for the thread library. */
char *saw_threadlib = 0;
/* Saw `-ljava' on command line. */
int saw_libjava = 0;
/* An array used to flag each argument that needs a bit set for
LANGSPEC, MATHLIB, WITHLIBC, or GCLIB. */
int *args;
/* By default, we throw on the math library. */
int need_math = 1;
/* By default, we throw in the thread library (if one is required).
*/
int need_thread = 1;
/* The total number of arguments with the new stuff. */
int argc;
/* The argument list. */
char **argv;
/* The number of libraries added in. */
int added_libraries;
/* The total number of arguments with the new stuff. */
int num_args = 1;
argc = *in_argc;
argv = *in_argv;
added_libraries = *in_added_libraries;
args = (int *) xmalloc (argc * sizeof (int));
bzero ((char *) args, argc * sizeof (int));
for (i = 1; i < argc; i++)
{
/* If the previous option took an argument, we swallow it here. */
if (quote)
{
quote = NULL;
continue;
}
/* We don't do this anymore, since we don't get them with minus
signs on them. */
if (argv[i][0] == '\0' || argv[i][1] == '\0')
continue;
if (argv[i][0] == '-')
{
if (library != 0 && (strcmp (argv[i], "-nostdlib") == 0
|| strcmp (argv[i], "-nodefaultlibs") == 0))
{
library = 0;
}
else if (strcmp (argv[i], "-lm") == 0
|| strcmp (argv[i], "-lmath") == 0
#ifdef ALT_LIBM
|| strcmp (argv[i], ALT_LIBM) == 0
#endif
)
{
args[i] |= MATHLIB;
need_math = 0;
}
else if (strncmp (argv[i], "-fmain=", 7) == 0)
main_class_name = argv[i] + 7;
else if (strcmp (argv[i], "-ljava") == 0)
saw_libjava = 1;
else if (strcmp (argv[i], "-lc") == 0)
args[i] |= WITHLIBC;
else if (strcmp (argv[i], "-lgc") == 0)
args[i] |= GCLIB;
#ifdef THREAD_NAME
else if (strcmp (argv[i], THREAD_NAME) == 0)
{
args[i] |= THREADLIB;
need_thread = 0;
}
#endif
else if (strcmp (argv[i], "-v") == 0)
{
saw_verbose_flag = 1;
if (argc == 2)
{
/* If they only gave us `-v', don't try to link
in libjava. */
library = 0;
}
}
else if (strncmp (argv[i], "-x", 2) == 0)
saw_speclang = 1;
else if (((argv[i][2] == '\0'
&& (char *)strchr ("bBVDUoeTuIYmLiA", argv[i][1]) != NULL)
|| strcmp (argv[i], "-Tdata") == 0))
quote = argv[i];
else if (library != 0 && ((argv[i][2] == '\0'
&& (char *) strchr ("cSEM", argv[i][1]) != NULL)
|| strcmp (argv[i], "-MM") == 0))
{
/* Don't specify libraries if we won't link, since that would
cause a warning. */
library = 0;
added -= 2;
}
else
/* Pass other options through. */
continue;
}
else
{
int len;
if (saw_speclang)
{
saw_speclang = 0;
continue;
}
/* If the filename ends in .c or .i, put options around it.
But not if a specified -x option is currently active. */
len = strlen (argv[i]);
if (len > 2
&& (argv[i][len - 1] == 'c' || argv[i][len - 1] == 'i')
&& argv[i][len - 2] == '.')
{
args[i] |= LANGSPEC;
added += 2;
}
}
}
if (quote)
(*fn) ("argument to `%s' missing\n", quote);
/* If we know we don't have to do anything, bail now. */
if (! added && ! library && main_class_name == NULL)
{
free (args);
return;
}
num_args = argc + added + need_math + need_thread;
if (main_class_name)
{
lang_specific_extra_outfiles++;
}
arglist = (char **) xmalloc (num_args * sizeof (char *));
/* NOTE: We start at 1 now, not 0. */
for (i = 0, j = 0; i < argc; i++, j++)
{
arglist[j] = argv[i];
if (strncmp (argv[i], "-fmain=", 7) == 0)
{
--j;
continue;
}
/* Make sure -ljava is before the math library, since libjava
itself uses those math routines. */
if (!saw_math && (args[i] & MATHLIB) && library)
{
--j;
saw_math = argv[i];
}
/* Likewise -ljava must come before -lc. */
if (!saw_libc && (args[i] & WITHLIBC) && library)
{
--j;
saw_libc = argv[i];
}
/* And -ljava must come before -lgc. */
if (!saw_gc && (args[i] & GCLIB) && library)
{
--j;
saw_gc = argv[i];
}
/* And -ljava must come before thread library. */
if (!saw_threadlib && (args[i] & THREADLIB) && library)
{
--j;
saw_threadlib = argv[i];
}
}
/* Add `-ljava' if we haven't already done so. */
if (library && ! saw_libjava)
{
arglist[j++] = "-ljava";
added_libraries++;
}
if (saw_math)
arglist[j++] = saw_math;
else if (library)
{
arglist[j++] = MATH_LIBRARY;
added_libraries++;
}
/* FIXME: we need a way to know when the GC library should be
added. Then we can add it if the user hasn't already. */
if (saw_gc)
arglist[j++] = saw_gc;
/* Thread library must come after GC library as well as after
-ljava. */
if (saw_threadlib)
arglist[j++] = saw_threadlib;
#ifdef THREAD_NAME
else if (library)
{
arglist[j++] = THREAD_NAME;
added_libraries++;
}
#endif
if (saw_libc)
arglist[j++] = saw_libc;
arglist[j] = NULL;
*in_argc = j;
*in_argv = arglist;
*in_added_libraries = added_libraries;
}
int
lang_specific_pre_link ()
{
if (main_class_name == NULL)
return 0;
input_filename = main_class_name;
input_filename_length = strlen (main_class_name);
return do_spec (jvgenmain_spec);
}

80
gcc/java/keyword.gperf Normal file
View file

@ -0,0 +1,80 @@
%{
/* Keyword definition for the GNU compiler for the Java(TM) language.
Copyright (C) 1997, 1998 Free Software Foundation, Inc.
Contributed by Alexandre Petit-Bianco (apbianco@cygnus.com)
This file is part of GNU CC.
GNU CC 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.
GNU CC 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, 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. */
%}
struct java_keyword { char *name; int token; };
%%
abstract, ABSTRACT_TK
default, DEFAULT_TK
if, IF_TK
private, PRIVATE_TK
throw, THROW_TK
boolean, BOOLEAN_TK
do, DO_TK
implements, IMPLEMENTS_TK
protected, PROTECTED_TK
throws, THROWS_TK
break, BREAK_TK
double, DOUBLE_TK
import, IMPORT_TK
public, PUBLIC_TK
transient, TRANSIENT_TK
byte, BYTE_TK
else, ELSE_TK
instanceof, INSTANCEOF_TK
return, RETURN_TK
try, TRY_TK
case, CASE_TK
extends, EXTENDS_TK
int, INT_TK
short, SHORT_TK
void, VOID_TK
catch, CATCH_TK
final, FINAL_TK
interface, INTERFACE_TK
static, STATIC_TK
volatile, VOLATILE_TK
char, CHAR_TK
finally, FINALLY_TK
long, LONG_TK
super, SUPER_TK
while, WHILE_TK
class, CLASS_TK
float, FLOAT_TK
native, NATIVE_TK
switch, SWITCH_TK
const, CONST_TK
for, FOR_TK
new, NEW_TK
synchronized, SYNCHRONIZED_TK
continue, CONTINUE_TK
goto, GOTO_TK
package, PACKAGE_TK
this, THIS_TK
# true, false and null aren't keyword. But we match them easily this way
true, TRUE_TK
false, FALSE_TK
null, NULL_TK

165
gcc/java/keyword.h Normal file
View file

@ -0,0 +1,165 @@
/* C code produced by gperf version 2.5 (GNU C++ version) */
/* Command-line: gperf -p -t -j1 -i 1 -g -o -N java_keyword -k1,3,$ keyword.gperf */
/* Keyword definitions for the GNU compiler for the Java(TM) language.
Copyright (C) 1997, 1998 Free Software Foundation, Inc.
Contributed by Alexandre Petit-Bianco (apbianco@cygnus.com)
This file is part of GNU CC.
GNU CC 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.
GNU CC 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, 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. */
struct java_keyword { char *name; int token; };
#define TOTAL_KEYWORDS 50
#define MIN_WORD_LENGTH 2
#define MAX_WORD_LENGTH 12
#define MIN_HASH_VALUE 6
#define MAX_HASH_VALUE 86
/* maximum key range = 81, duplicates = 0 */
#ifdef __GNUC__
inline
#endif
static unsigned int
hash (str, len)
register char *str;
register int unsigned len;
{
static unsigned char asso_values[] =
{
87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
87, 87, 87, 87, 87, 87, 87, 18, 37, 38,
27, 1, 30, 3, 12, 8, 87, 2, 11, 87,
8, 1, 5, 87, 24, 1, 1, 30, 2, 36,
87, 1, 87, 87, 87, 87, 87, 87,
};
register int hval = len;
switch (hval)
{
default:
case 3:
hval += asso_values[str[2]];
case 2:
case 1:
hval += asso_values[str[0]];
break;
}
return hval + asso_values[str[len - 1]];
}
#ifdef __GNUC__
inline
#endif
struct java_keyword *
java_keyword (str, len)
register char *str;
register unsigned int len;
{
static struct java_keyword wordlist[] =
{
{"",}, {"",}, {"",}, {"",}, {"",}, {"",},
{"try", TRY_TK},
{"else", ELSE_TK},
{"short", SHORT_TK},
{"goto", GOTO_TK},
{"extends", EXTENDS_TK},
{"",}, {"",},
{"int", INT_TK},
{"this", THIS_TK},
{"",},
{"native", NATIVE_TK},
{"",}, {"",},
{"interface", INTERFACE_TK},
{"import", IMPORT_TK},
{"private", PRIVATE_TK},
{"volatile", VOLATILE_TK},
{"",},
{"implements", IMPLEMENTS_TK},
{"",},
{"long", LONG_TK},
{"switch", SWITCH_TK},
{"abstract", ABSTRACT_TK},
{"transient", TRANSIENT_TK},
{"do", DO_TK},
{"",},
{"throws", THROWS_TK},
{"",},
{"null", NULL_TK},
{"super", SUPER_TK},
{"true", TRUE_TK},
{"float", FLOAT_TK},
{"",},
{"return", RETURN_TK},
{"if", IF_TK},
{"void", VOID_TK},
{"protected", PROTECTED_TK},
{"byte", BYTE_TK},
{"case", CASE_TK},
{"break", BREAK_TK},
{"finally", FINALLY_TK},
{"false", FALSE_TK},
{"synchronized", SYNCHRONIZED_TK},
{"instanceof", INSTANCEOF_TK},
{"while", WHILE_TK},
{"package", PACKAGE_TK},
{"const", CONST_TK},
{"boolean", BOOLEAN_TK},
{"final", FINAL_TK},
{"continue", CONTINUE_TK},
{"catch", CATCH_TK},
{"",}, {"",}, {"",}, {"",}, {"",},
{"class", CLASS_TK},
{"static", STATIC_TK},
{"double", DOUBLE_TK},
{"default", DEFAULT_TK},
{"throw", THROW_TK},
{"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
{"",}, {"",}, {"",}, {"",}, {"",},
{"for", FOR_TK},
{"",},
{"new", NEW_TK},
{"char", CHAR_TK},
{"",},
{"public", PUBLIC_TK},
};
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
{
register int key = hash (str, len);
if (key <= MAX_HASH_VALUE && key >= 0)
{
register char *s = wordlist[key].name;
if (*s == *str && !strcmp (str + 1, s + 1))
return &wordlist[key];
}
}
return 0;
}

35
gcc/java/lang-options.h Normal file
View file

@ -0,0 +1,35 @@
/* Switch definitions for the GNU compiler for the Java(TM) language.
Copyright (C) 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC 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.
GNU CC 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, 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. */
/* This is the contribution to the `lang_options' array in gcc.c for
java. */
DEFINE_LANG_NAME ("Java")
{ "-fbounds-check", "" },
{ "-fno-bounds-check", "Disable automatic array bounds checking" },
{ "-fassume-compiled", "Make is_compiled_class return 1"},
{ "-fno-assume-compiled", "" },
{ "-femit-class-file", "" },
{ "-femit-class-files", "Dump class files to <name>.class" },

38
gcc/java/lang-specs.h Normal file
View file

@ -0,0 +1,38 @@
/* Definitions for specs for the GNU compiler for the Java(TM) language.
Copyright (C) 1996 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC 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.
GNU CC 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, 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. */
/* This is the contribution to the `default_compilers' array in gcc.c for
Java. */
{".java", "@java" },
{".class", "@java" },
{"@java",
"%{!M:%{!MM:%{!E:jc1 %i %1 %2 %{!Q:-quiet} %{d*} %{m*} %{a}\
%{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi}\
%{traditional} %{v:-version} %{pg:-p} %{p}\
%{f*} %{+e*} %{aux-info*}\
%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
%{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
%{!S:as %a %Y\
%{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}\
%{!pipe:%g.s} %A\n }}}}"},

406
gcc/java/lang.c Normal file
View file

@ -0,0 +1,406 @@
/* Java(TM) language-specific utility routines.
Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC 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.
GNU CC 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, 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. */
/* Hacked by Per Bothner <bothner@cygnus.com> February 1996. */
#include <stdio.h>
#include "config.h"
#include "tree.h"
#include "input.h"
#include "java-tree.h"
#include "jcf.h"
int compiling_from_source;
char *language_string = "GNU Java";
/* Nonzero if we want to automatically do array bounds checking;
on by default. Use -fno-bounds-check to disable. */
int flag_bounds_check = 1;
/* Nonzero if we should make is_compiled_class always return 1 for
appropriate classes that we're referencing. */
int flag_assume_compiled = 1;
int flag_emit_class_files = 0;
/* From gcc/flags.h, and idicates if exceptions are turned on or not. */
extern int flag_new_exceptions;
extern int flag_exceptions;
/* Table of language-dependent -f options.
STRING is the option name. VARIABLE is the address of the variable.
ON_VALUE is the value to store in VARIABLE
if `-fSTRING' is seen as an option.
(If `-fno-STRING' is seen as an option, the opposite value is stored.) */
static struct { char *string; int *variable; int on_value;} lang_f_options[] =
{
{"bounds-check", &flag_bounds_check, 1},
{"assume-compiled", &flag_assume_compiled, 1},
{"emit-class-file", &flag_emit_class_files, 1},
{"emit-class-files", &flag_emit_class_files, 1},
};
JCF main_jcf[1];
JCF *current_jcf;
/*
* process java-specific compiler command-line options
*/
int
lang_decode_option (argc, argv)
int argc;
char **argv;
{
char *p = argv[0];
if (p[0] == '-' && p[1] == 'f')
{
/* Some kind of -f option.
P's value is the option sans `-f'.
Search for it in the table of options. */
int found = 0, j;
p += 2;
for (j = 0;
!found && j < sizeof (lang_f_options) / sizeof (lang_f_options[0]);
j++)
{
if (!strcmp (p, lang_f_options[j].string))
{
*lang_f_options[j].variable = lang_f_options[j].on_value;
/* A goto here would be cleaner,
but breaks the vax pcc. */
found = 1;
}
if (p[0] == 'n' && p[1] == 'o' && p[2] == '-'
&& ! strcmp (p+3, lang_f_options[j].string))
{
*lang_f_options[j].variable = ! lang_f_options[j].on_value;
found = 1;
}
}
return found;
}
return 0;
}
FILE *finput;
char *
init_parse (filename)
char *filename;
{
/* Open input file. */
if (filename == 0 || !strcmp (filename, "-"))
{
finput = stdin;
filename = "stdin";
}
else
finput = fopen (filename, "r");
if (finput == 0)
pfatal_with_name (filename);
#ifdef IO_BUFFER_SIZE
setvbuf (finput, (char *) xmalloc (IO_BUFFER_SIZE), _IOFBF, IO_BUFFER_SIZE);
#endif
init_lex ();
return filename;
}
void
finish_parse ()
{
fclose (finput);
}
/* Buffer used by lang_printable_name. */
static char *decl_buf = NULL;
/* Allocated size of decl_buf. */
static int decl_buflen = 0;
/* Length of used part of decl_buf; position for next character. */
static int decl_bufpos = 0;
/* Append the string STR to decl_buf.
It length is given by LEN; -1 means the string is nul-terminated. */
static void
put_decl_string (str, len)
char *str;
int len;
{
if (len < 0)
len = strlen (str);
if (decl_bufpos + len >= decl_buflen)
{
if (decl_buf == NULL)
{
decl_buflen = len + 100;
decl_buf = (char *) xmalloc (decl_buflen);
}
else
{
decl_buflen *= 2;
decl_buf = (char *) xrealloc (decl_buf, decl_buflen);
}
}
strcpy (decl_buf + decl_bufpos, str);
decl_bufpos += len;
}
/* Append to decl_buf a printable name for NODE. */
static void
put_decl_node (node)
tree node;
{
int was_pointer = 0;
if (TREE_CODE (node) == POINTER_TYPE)
{
node = TREE_TYPE (node);
was_pointer = 1;
}
if (TREE_CODE_CLASS (TREE_CODE (node)) == 'd'
&& DECL_NAME (node) != NULL_TREE)
{
#if 0
if (DECL_CONTEXT (node) != NULL_TREE)
{
put_decl_node (DECL_CONTEXT (node));
put_decl_string (".", 1);
}
#endif
put_decl_node (DECL_NAME (node));
if (TREE_CODE (node) == FUNCTION_DECL && TREE_TYPE (node) != NULL_TREE)
{
int i = 0;
tree args = TYPE_ARG_TYPES (TREE_TYPE (node));
if (TREE_CODE (TREE_TYPE (node)) == METHOD_TYPE)
args = TREE_CHAIN (args);
put_decl_string ("(", 1);
for ( ; args != NULL_TREE; args = TREE_CHAIN (args), i++)
{
if (i > 0)
put_decl_string (",", 1);
put_decl_node (TREE_VALUE (args));
}
put_decl_string (")", 1);
}
}
else if (TREE_CODE_CLASS (TREE_CODE (node)) == 't'
&& TYPE_NAME (node) != NULL_TREE)
{
if (TREE_CODE (node) == RECORD_TYPE && TYPE_ARRAY_P (node))
{
put_decl_node (TYPE_ARRAY_ELEMENT (node));
put_decl_string("[]", 2);
}
else if (node == promoted_byte_type_node)
put_decl_string ("byte", 4);
else if (node == promoted_short_type_node)
put_decl_string ("short", 5);
else if (node == promoted_char_type_node)
put_decl_string ("char", 4);
else if (node == promoted_boolean_type_node)
put_decl_string ("boolean", 7);
else if (node == void_type_node && was_pointer)
put_decl_string ("null", 4);
else
put_decl_node (TYPE_NAME (node));
}
else if (TREE_CODE (node) == IDENTIFIER_NODE)
put_decl_string (IDENTIFIER_POINTER (node), IDENTIFIER_LENGTH (node));
else
put_decl_string ("<unknown>", -1);
}
/* Return a user-friendly name for DECL.
The resulting string is only valid until the next call.
The value of the hook decl_printable_name is this function,
which is also called directly by lang_print_error. */
char *
lang_printable_name (decl, v)
tree decl;
int v;
{
decl_bufpos = 0;
put_decl_node (decl);
put_decl_string ("", 1);
return decl_buf;
}
/* Print on stderr the current class and method context. This function
is the value of the hook print_error_function, called from toplev.c. */
void
lang_print_error (file)
char *file;
{
static tree last_error_function_context = NULL_TREE;
static tree last_error_function = NULL;
if (current_function_decl != NULL
&& DECL_CONTEXT (current_function_decl) != last_error_function_context)
{
if (file)
fprintf (stderr, "%s: ", file);
last_error_function_context = DECL_CONTEXT (current_function_decl);
fprintf (stderr, "In class `%s':\n",
lang_printable_name (last_error_function_context));
}
if (last_error_function != current_function_decl)
{
if (file)
fprintf (stderr, "%s: ", file);
if (current_function_decl == NULL)
fprintf (stderr, "At top level:\n");
else
{
char *name = lang_printable_name (current_function_decl, 2);
fprintf (stderr, "In method `%s':\n", name);
}
last_error_function = current_function_decl;
}
}
void
lang_init ()
{
extern struct rtx_def * java_lang_expand_expr ();
extern struct rtx_def * (*lang_expand_expr) ();
extern void (*print_error_function) PROTO((char *));
#if 0
extern int flag_minimal_debug;
flag_minimal_debug = 0;
#endif
decl_printable_name = lang_printable_name;
print_error_function = lang_print_error;
lang_expand_expr = java_lang_expand_expr;
JCF_ZERO (main_jcf);
main_jcf->read_state = finput;
main_jcf->filbuf = jcf_filbuf_from_stdio;
current_jcf = main_jcf;
flag_exceptions = 1;
}
/* This doesn't do anything on purpose. It's used to satisfy the
print_error_function hook we don't print error messages with bogus
function prototypes. */
void java_dummy_print (s)
char *s;
{
}
/* Called to install the PRINT_ERROR_FUNCTION hook differently
according to LEVEL. LEVEL is 1 during early parsing, when function
prototypes aren't fully resolved. print_error_function is set so it
doesn't print incomplete function prototypes. When LEVEL is 2,
function prototypes are fully resolved and can be printed when
reporting errors. */
void lang_init_source (level)
int level;
{
extern void (*print_error_function) PROTO((char *));
if (level == 1)
print_error_function = java_dummy_print;
else
print_error_function = lang_print_error;
}
void
lang_init_options ()
{
flag_new_exceptions = 1;
}
void
lang_finish ()
{
}
char*
lang_identify ()
{
return "Java";
}
/* Hooks for print_node. */
void
print_lang_decl (file, node, indent)
FILE *file;
tree node;
int indent;
{
}
void
print_lang_type (file, node, indent)
FILE *file;
tree node;
int indent;
{
}
void
print_lang_identifier (file, node, indent)
FILE *file;
tree node;
int indent;
{
}
void
print_lang_statistics ()
{
}
/* used by print-tree.c */
void
lang_print_xnode (file, node, indent)
FILE *file;
tree node;
int indent;
{
}

1355
gcc/java/lex.c Normal file

File diff suppressed because it is too large Load diff

512
gcc/java/lex.h Normal file
View file

@ -0,0 +1,512 @@
/* Language lexer definitions for the GNU compiler for the Java(TM) language.
Copyright (C) 1997, 1998 Free Software Foundation, Inc.
Contributed by Alexandre Petit-Bianco (apbianco@cygnus.com)
This file is part of GNU CC.
GNU CC 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.
GNU CC 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, 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. */
#ifndef JV_LEX_H
#define JV_LEX_H
/* Extern global variables declarations */
extern FILE *finput;
extern int lineno;
extern char *classpath;
/* A Unicode character, as read from the input file */
typedef unsigned short unicode_t;
/* Function declaration */
static int java_lineterminator ();
static char *java_sprint_unicode ();
static void java_unicode_2_utf8 ();
static void java_lex_error ();
static void java_store_unicode ();
/* Debug macro to print-out what we match */
#ifdef JAVA_LEX_DEBUG
#ifdef JAVA_LEX_DEBUG_CHAR
#define JAVA_LEX_CHAR(c) printf ("java_lex:%d: char '%c'.%d\n", \
lineno, (c < 128 ? c : '.'), c);
#else
#define JAVA_LEX_CHAR(c)
#endif
#define JAVA_LEX_KW(c) printf ("java_lex:%d: keyword: '%s'\n", lineno,c)
#define JAVA_LEX_ID(s) printf ("java_lex:%d: ID: '%s'\n", \
lineno, \
(all_ascii ? s : "<U>"))
#define JAVA_LEX_LIT(s, r) printf ("java_lex:%d: literal '%s'_%d\n", \
lineno, s, r)
#define JAVA_LEX_CHAR_LIT(s) printf ("java_lex:%d: literal '%d'\n", lineno, s)
#define JAVA_LEX_STR_LIT(s) { \
int i; \
printf ("java_lex:%d: literal '%s'\n", \
lineno, s); \
}
#define JAVA_LEX_SEP(c) printf ("java_lex:%d: separator '%c'\n",lineno,c)
#define JAVA_LEX_OP(c) printf ("java_lex:%d: operator '%s'\n", lineno,c)
#else
#define JAVA_LEX_CHAR(c)
#define JAVA_LEX_KW(c)
#define JAVA_LEX_ID(s)
#define JAVA_LEX_LIT(s,r)
#define JAVA_LEX_CHAR_LIT(s)
#define JAVA_LEX_STR_LIT(s)
#define JAVA_LEX_SEP(c)
#define JAVA_LEX_OP(s)
#endif
/* Line information containers */
struct java_line {
unicode_t *line; /* The line's unicode */
char *unicode_escape_p; /* The maching char was a unicode escape */
unicode_t ahead[1]; /* Character ahead */
char unicode_escape_ahead_p; /* Character ahead is a unicode escape */
int max; /* buffer's max size */
int size; /* number of unicodes */
int current; /* Current position, unicode based */
int char_col; /* Current position, input char based */
int lineno; /* Its line number */
int white_space_only; /* If it contains only white spaces */
};
#define JAVA_COLUMN_DELTA(p) \
(ctxp->c_line->unicode_escape_p [ctxp->c_line->current+(p)] ? 6 : \
(ctxp->c_line->line [ctxp->c_line->current+(p)] == '\t' ? 8 : 1))
struct java_error {
struct java_line *line;
int error;
};
typedef struct _java_lc {
int line;
int col;
} java_lc;
#define JAVA_LINE_MAX 80
/* Macro to read and unread chars */
#define UNGETC(c) ctxp->unget_utf8_value = (c);
#define GETC() getc(finput)
/* Build a location compound integer */
#define BUILD_LOCATION() ((ctxp->elc.line << 12) | (ctxp->elc.col & 0xfff))
/* Those macros are defined differently if we compile jc1-lite
(JC1_LITE defined) or jc1. */
#ifdef JC1_LITE
#define DCONST0 0
#define HOST_WIDE_INT long
#define HOST_BITS_PER_WIDE_INT 64
#define HOST_BITS_PER_CHAR 8
#define REAL_VALUE_TYPE int
#define SET_FLOAT_HANDLER(H)
#define GET_IDENTIFIER(S) xstrdup ((S))
#define REAL_VALUE_ATOF(LIT,MODE) 0
#define REAL_VALUE_ISINF(VALUE) 0
#define REAL_VALUE_ISNAN(VALUE) 0
#define SET_REAL_VALUE_ATOF(TARGET,SOURCE)
#define FLOAT_TYPE_NODE 0
#define DOUBLE_TYPE_NODE 0
#define SET_MODIFIER_CTX(TOKEN) java_lval->value = (TOKEN)
#define GET_TYPE_PRECISION(NODE) 4
#define BUILD_OPERATOR(TOKEN) return TOKEN
#define BUILD_OPERATOR2(TOKEN) return TOKEN
#define SET_LVAL_NODE(NODE)
#define SET_LVAL_NODE_TYPE(NODE, TYPE)
#define BUILD_ID_WFL(EXP) (EXP)
#define JAVA_FLOAT_RANGE_ERROR(S) {}
#define JAVA_INTEGRAL_RANGE_ERROR(S) {}
#else
static tree build_wfl_node ();
#define SET_FLOAT_HANDLER(H) set_float_handler ((H))
#define DCONST0 dconst0
#define GET_IDENTIFIER(S) get_identifier ((S))
#define SET_REAL_VALUE_ATOF(TARGET,SOURCE) (TARGET) = (SOURCE)
#define FLOAT_TYPE_NODE float_type_node
#define DOUBLE_TYPE_NODE double_type_node
/* Set modifier_ctx according to TOKEN */
#define SET_MODIFIER_CTX(TOKEN) \
{ \
ctxp->modifier_ctx [(TOKEN)-PUBLIC_TK] = build_wfl_node (NULL_TREE); \
java_lval->value = (TOKEN)-PUBLIC_TK; \
}
/* Type precision for long */
#define GET_TYPE_PRECISION(NODE) TYPE_PRECISION (long_type_node) / 8;
/* Build an operator tree node and return TOKEN */
#define BUILD_OPERATOR(TOKEN) \
{ \
java_lval->operator.token = (TOKEN); \
java_lval->operator.location = BUILD_LOCATION(); \
return (TOKEN); \
}
/* Build an operator tree node but return ASSIGN_ANY_TK */
#define BUILD_OPERATOR2(TOKEN) \
{ \
java_lval->operator.token = (TOKEN); \
java_lval->operator.location = BUILD_LOCATION(); \
return ASSIGN_ANY_TK; \
}
/* Set java_lval->node and TREE_TYPE(java_lval->node) in macros */
#define SET_LVAL_NODE(NODE) java_lval->node = (NODE)
#define SET_LVAL_NODE_TYPE(NODE,TYPE) \
{ \
java_lval->node = (NODE); \
TREE_TYPE (java_lval->node) = (TYPE); \
}
/* Wrap identifier around a wfl */
#define BUILD_ID_WFL(EXP) build_wfl_node ((EXP))
/* Special ways to report error on numeric literals */
#define JAVA_FLOAT_RANGE_ERROR(m) \
{ \
char msg [1024]; \
int i = ctxp->c_line->current; \
ctxp->c_line->current = number_beginning; \
sprintf (msg, "Floating pointer literal exceeds range of `%s'", (m)); \
java_lex_error (msg, 0); \
ctxp->c_line->current = i; \
value = dconst0; \
}
#define JAVA_INTEGRAL_RANGE_ERROR(m) \
{ \
int i = ctxp->c_line->current; \
ctxp->c_line->current = number_beginning; \
java_lex_error (m, 0); \
ctxp->c_line->current = i; \
}
#endif /* Definitions for jc1 compilation only */
/* Macros to decode character ranges */
#define RANGE(c, l, h) (((c) >= l && (c) <= h))
#define JAVA_WHITE_SPACE_P(c) (c == ' ' || c == '\t' || c == '\f')
#define JAVA_ID_CHAR_P(c) ((c < 128 && (RANGE (c, 'A', 'Z') || \
RANGE (c, 'a', 'z') || \
RANGE (c, '0', '9') || \
c == '_' || \
c == '$')) || \
(c > 127 && java_letter_or_digit_p (c)))
#define JAVA_ASCII_DIGIT(c) RANGE(c,'0', '9')
#define JAVA_ASCII_OCTDIGIT(c) RANGE(c,'0', '7')
#define JAVA_ASCII_HEXDIGIT(c) (RANGE(c,'0', '9') || \
RANGE(c,'a', 'f') || \
RANGE(c,'A', 'F'))
#define JAVA_ASCII_FPCHAR(c) (RANGE(c,'d', 'f') || RANGE(c,'D', 'F') || \
c == '.' || JAVA_ASCII_DIGIT (c))
#define JAVA_FP_SUFFIX(c) (c == 'D' || c == 'd' || c == 'f' || c == 'F')
#define JAVA_FP_EXP(c) (c == 'E' || c == 'F')
#define JAVA_FP_PM(c) (c == '-' || c == '+')
#define JAVA_ASCII_LETTER(c) (RANGE(c,'a', 'z') || RANGE(c,'A', 'Z'))
#define JAVA_DIGIT_P(c) \
(RANGE (c, 0x030, 0x039) || /* ISO-Latin-1 (and ASCII) digits ('0'-'9') */ \
RANGE (c, 0x660, 0x669) || /* Arabic-Indic digits */ \
RANGE (c, 0x6F0, 0x6F9) || /* Eastern Arabic-Indic digits */ \
RANGE (c, 0x966, 0x96F) || /* Devanagari digits */ \
RANGE (c, 0x9E6, 0x9EF) || /* Bengali digits */ \
RANGE (c, 0xA66, 0xA6F) || /* Gurmukhi digits */ \
RANGE (c, 0xAE6, 0xAEF) || /* Gujarati digits */ \
RANGE (c, 0xB66, 0xB6F) || /* Oriya digits */ \
RANGE (c, 0xBE7, 0xBEF) || /* Tamil digits */ \
RANGE (c, 0xC66, 0xC6F) || /* Telugu digits */ \
RANGE (c, 0xCE6, 0xCEF) || /* Kannada digits */ \
RANGE (c, 0xD66, 0xD6F) || /* Malayalam digits */ \
RANGE (c, 0xE50, 0xE59) || /* Thai digits */ \
RANGE (c, 0xED0, 0xED9)) /* Lao digits */
/* This is not to be used as a stand alone macro. Use JAVA_ID_CHAR_P()
or the forcoming JAVA_LETTER_OR_DIGIT_P() instead.
It need to be split by region. FIXME. */
#define _JAVA_LETTER_OR_DIGIT_P(c) \
(RANGE (c, 0x00C0, 0x00D6) || \
RANGE (c, 0x00D8, 0x00F6) || \
RANGE (c, 0x00F8, 0x01F5) || \
RANGE (c, 0x01FA, 0x0217) || \
RANGE (c, 0x0250, 0x02A8) || \
RANGE (c, 0x02B0, 0x02DE) || \
RANGE (c, 0x02E0, 0x02E9) || \
RANGE (c, 0x0300, 0x0345) || \
RANGE (c, 0x0360, 0x0361) || \
RANGE (c, 0x0374, 0x0375) || \
c == 0x037A || \
c == 0x037E || \
RANGE (c, 0x0384, 0x038A) || \
c == 0x038C || \
c == 0x038E || \
RANGE (c, 0x038F, 0x03A1) || \
RANGE (c, 0x03A3, 0x03CE) || \
RANGE (c, 0x03D0, 0x03D6) || \
RANGE (c, 0x03DA, 0x03E2) || \
c == 0x03DA || \
c == 0x03DC || \
c == 0x03DE || \
c == 0x03E0 || \
RANGE (c, 0x03E2, 0x03F3) || \
RANGE (c, 0x0401, 0x040C) || \
RANGE (c, 0x040E, 0x044F) || \
RANGE (c, 0x0451, 0x045C) || \
RANGE (c, 0x045E, 0x0486) || \
RANGE (c, 0x0490, 0x04C4) || \
RANGE (c, 0x04C7, 0x04C8) || \
RANGE (c, 0x04CB, 0x04CC) || \
RANGE (c, 0x04D0, 0x04EB) || \
RANGE (c, 0x04EE, 0x04F5) || \
RANGE (c, 0x04F8, 0x04F9) || \
RANGE (c, 0x0531, 0x0556) || \
RANGE (c, 0x0559, 0x055F) || \
RANGE (c, 0x0561, 0x0587) || \
c == 0x0589 || \
RANGE (c, 0x05B0, 0x05B9) || \
RANGE (c, 0x05BB, 0x05C3) || \
RANGE (c, 0x05D0, 0x05EA) || \
RANGE (c, 0x05F0, 0x05F4) || \
c == 0x060C || \
c == 0x061B || \
c == 0x061F || \
c == 0x0621 || \
RANGE (c, 0x0622, 0x063A) || \
RANGE (c, 0x0640, 0x0652) || \
RANGE (c, 0x0660, 0x066D) || \
RANGE (c, 0x0670, 0x06B7) || \
RANGE (c, 0x06BA, 0x06BE) || \
RANGE (c, 0x06C0, 0x06CE) || \
RANGE (c, 0x06D0, 0x06ED) || \
RANGE (c, 0x06F0, 0x06F9) || \
RANGE (c, 0x0901, 0x0903) || \
RANGE (c, 0x0905, 0x0939) || \
RANGE (c, 0x093C, 0x094D) || \
RANGE (c, 0x0950, 0x0954) || \
RANGE (c, 0x0958, 0x0970) || \
RANGE (c, 0x0981, 0x0983) || \
RANGE (c, 0x0985, 0x098C) || \
RANGE (c, 0x098F, 0x0990) || \
RANGE (c, 0x0993, 0x09A8) || \
RANGE (c, 0x09AA, 0x09B0) || \
c == 0x09B2 || \
RANGE (c, 0x09B6, 0x09B9) || \
c == 0x09BC || \
c == 0x09BE || \
RANGE (c, 0x09BF, 0x09C4) || \
RANGE (c, 0x09C7, 0x09C8) || \
RANGE (c, 0x09CB, 0x09CD) || \
c == 0x09D7 || \
RANGE (c, 0x09DC, 0x09DD) || \
RANGE (c, 0x09DF, 0x09E3) || \
RANGE (c, 0x09E6, 0x09FA) || \
c == 0x0A02 || \
RANGE (c, 0x0A05, 0x0A0A) || \
RANGE (c, 0x0A0F, 0x0A10) || \
RANGE (c, 0x0A13, 0x0A28) || \
RANGE (c, 0x0A2A, 0x0A30) || \
RANGE (c, 0x0A32, 0x0A33) || \
RANGE (c, 0x0A35, 0x0A36) || \
RANGE (c, 0x0A38, 0x0A39) || \
c == 0x0A3C || \
c == 0x0A3E || \
RANGE (c, 0x0A3F, 0x0A42) || \
RANGE (c, 0x0A47, 0x0A48) || \
RANGE (c, 0x0A4B, 0x0A4D) || \
RANGE (c, 0x0A59, 0x0A5C) || \
c == 0x0A5E || \
RANGE (c, 0x0A66, 0x0A74) || \
RANGE (c, 0x0A81, 0x0A83) || \
RANGE (c, 0x0A85, 0x0A8B) || \
c == 0x0A8D || \
c == 0x0A8F || \
RANGE (c, 0x0A90, 0x0A91) || \
RANGE (c, 0x0A93, 0x0AA8) || \
RANGE (c, 0x0AAA, 0x0AB0) || \
RANGE (c, 0x0AB2, 0x0AB3) || \
RANGE (c, 0x0AB5, 0x0AB9) || \
RANGE (c, 0x0ABC, 0x0AC5) || \
RANGE (c, 0x0AC7, 0x0AC9) || \
RANGE (c, 0x0ACB, 0x0ACD) || \
c == 0x0AD0 || \
c == 0x0AE0 || \
RANGE (c, 0x0AE6, 0x0AEF) || \
RANGE (c, 0x0B01, 0x0B03) || \
RANGE (c, 0x0B05, 0x0B0C) || \
RANGE (c, 0x0B0F, 0x0B10) || \
RANGE (c, 0x0B13, 0x0B28) || \
RANGE (c, 0x0B2A, 0x0B30) || \
RANGE (c, 0x0B32, 0x0B33) || \
RANGE (c, 0x0B36, 0x0B39) || \
RANGE (c, 0x0B3C, 0x0B43) || \
RANGE (c, 0x0B47, 0x0B48) || \
RANGE (c, 0x0B4B, 0x0B4D) || \
RANGE (c, 0x0B56, 0x0B57) || \
RANGE (c, 0x0B5C, 0x0B5D) || \
RANGE (c, 0x0B5F, 0x0B61) || \
RANGE (c, 0x0B66, 0x0B70) || \
RANGE (c, 0x0B82, 0x0B83) || \
RANGE (c, 0x0B85, 0x0B8A) || \
RANGE (c, 0x0B8E, 0x0B90) || \
RANGE (c, 0x0B92, 0x0B95) || \
RANGE (c, 0x0B99, 0x0B9A) || \
c == 0x0B9C || \
c == 0x0B9E || \
c == 0x0B9F || \
RANGE (c, 0x0BA3, 0x0BA4) || \
RANGE (c, 0x0BA8, 0x0BAA) || \
RANGE (c, 0x0BAE, 0x0BB5) || \
RANGE (c, 0x0BB7, 0x0BB9) || \
RANGE (c, 0x0BBE, 0x0BC2) || \
RANGE (c, 0x0BC6, 0x0BC8) || \
RANGE (c, 0x0BCA, 0x0BCD) || \
c == 0x0BD7 || \
RANGE (c, 0x0BE7, 0x0BF2) || \
RANGE (c, 0x0C01, 0x0C03) || \
RANGE (c, 0x0C05, 0x0C0C) || \
RANGE (c, 0x0C0E, 0x0C10) || \
RANGE (c, 0x0C12, 0x0C28) || \
RANGE (c, 0x0C2A, 0x0C33) || \
RANGE (c, 0x0C35, 0x0C39) || \
RANGE (c, 0x0C3E, 0x0C44) || \
RANGE (c, 0x0C46, 0x0C48) || \
RANGE (c, 0x0C4A, 0x0C4D) || \
RANGE (c, 0x0C55, 0x0C56) || \
RANGE (c, 0x0C60, 0x0C61) || \
RANGE (c, 0x0C66, 0x0C6F) || \
RANGE (c, 0x0C82, 0x0C83) || \
RANGE (c, 0x0C85, 0x0C8C) || \
RANGE (c, 0x0C8E, 0x0C90) || \
RANGE (c, 0x0C92, 0x0CA8) || \
RANGE (c, 0x0CAA, 0x0CB3) || \
RANGE (c, 0x0CB5, 0x0CB9) || \
RANGE (c, 0x0CBE, 0x0CC4) || \
RANGE (c, 0x0CC6, 0x0CC8) || \
RANGE (c, 0x0CCA, 0x0CCD) || \
RANGE (c, 0x0CD5, 0x0CD6) || \
c == 0x0CDE || \
c == 0x0CE0 || \
c == 0x0CE1 || \
RANGE (c, 0x0CE6, 0x0CEF) || \
RANGE (c, 0x0D02, 0x0D03) || \
RANGE (c, 0x0D05, 0x0D0C) || \
RANGE (c, 0x0D0E, 0x0D10) || \
RANGE (c, 0x0D12, 0x0D28) || \
RANGE (c, 0x0D2A, 0x0D39) || \
RANGE (c, 0x0D3E, 0x0D43) || \
RANGE (c, 0x0D46, 0x0D48) || \
RANGE (c, 0x0D4A, 0x0D4D) || \
c == 0x0D57 || \
RANGE (c, 0x0D60, 0x0D61) || \
RANGE (c, 0x0D66, 0x0D6F) || \
RANGE (c, 0x0E01, 0x0E3A) || \
RANGE (c, 0x0E3F, 0x0E5B) || \
RANGE (c, 0x0E81, 0x0E82) || \
c == 0x0E84 || \
RANGE (c, 0x0E87, 0x0E88) || \
c == 0x0E8A || \
c == 0x0E8D || \
RANGE (c, 0x0E94, 0x0E97) || \
RANGE (c, 0x0E99, 0x0E9F) || \
RANGE (c, 0x0EA1, 0x0EA3) || \
c == 0x0EA5 || \
c == 0x0EA7 || \
RANGE (c, 0x0EAA, 0x0EAB) || \
RANGE (c, 0x0EAD, 0x0EB9) || \
RANGE (c, 0x0EBB, 0x0EBD) || \
RANGE (c, 0x0EC0, 0x0EC4) || \
c == 0x0EC6 || \
c == 0x0EC8 || \
RANGE (c, 0x0EC9, 0x0ECD) || \
RANGE (c, 0x0ED0, 0x0ED9) || \
RANGE (c, 0x0EDC, 0x0EDD) || \
RANGE (c, 0x10A0, 0x10C5) || \
RANGE (c, 0x10D0, 0x10F6) || \
c == 0x10FB || \
RANGE (c, 0x1100, 0x1159) || \
RANGE (c, 0x115F, 0x11A2) || \
RANGE (c, 0x11A8, 0x11F9) || \
RANGE (c, 0x1E00, 0x1E9A) || \
RANGE (c, 0x1EA0, 0x1EF9) || \
RANGE (c, 0x1F00, 0x1F15) || \
RANGE (c, 0x1F18, 0x1F1D) || \
RANGE (c, 0x1F20, 0x1F45) || \
RANGE (c, 0x1F48, 0x1F4D) || \
RANGE (c, 0x1F50, 0x1F57) || \
c == 0x1F59 || \
c == 0x1F5B || \
c == 0x1F5D || \
RANGE (c, 0x1F5F, 0x1F7D) || \
RANGE (c, 0x1F80, 0x1FB4) || \
RANGE (c, 0x1FB6, 0x1FC4) || \
RANGE (c, 0x1FC6, 0x1FD3) || \
RANGE (c, 0x1FD6, 0x1FDB) || \
RANGE (c, 0x1FDD, 0x1FEF) || \
RANGE (c, 0x1FF2, 0x1FF4) || \
RANGE (c, 0x1FF6, 0x1FFE) || \
RANGE (c, 0x3041, 0x3094) || \
RANGE (c, 0x3099, 0x309E) || \
RANGE (c, 0x30A1, 0x30FE) || \
RANGE (c, 0x3105, 0x312C) || \
RANGE (c, 0x3131, 0x318E) || \
RANGE (c, 0x3190, 0x319F) || \
RANGE (c, 0x3200, 0x321C) || \
RANGE (c, 0x3220, 0x3243) || \
RANGE (c, 0x3260, 0x327B) || \
RANGE (c, 0x327F, 0x32B0) || \
RANGE (c, 0x32C0, 0x32CB) || \
RANGE (c, 0x32D0, 0x32FE) || \
RANGE (c, 0x3300, 0x3376) || \
RANGE (c, 0x337B, 0x33DD) || \
RANGE (c, 0x33E0, 0x33FE) || \
RANGE (c, 0x3400, 0x9FA5) || \
RANGE (c, 0xF900, 0xFA2D) || \
RANGE (c, 0xFB00, 0xFB06) || \
RANGE (c, 0xFB13, 0xFB17) || \
RANGE (c, 0xFB1E, 0xFB36) || \
RANGE (c, 0xFB38, 0xFB3C) || \
c == 0xFB3E || \
c == 0xFB40 || \
c == 0xFB41 || \
c == 0xFB43 || \
c == 0xFB44 || \
c == 0xFB46 || \
RANGE (c, 0xFB47, 0xFBB1) || \
RANGE (c, 0xFBD3, 0xFD3F) || \
RANGE (c, 0xFD50, 0xFD8F) || \
RANGE (c, 0xFD92, 0xFDC7) || \
RANGE (c, 0xFDF0, 0xFDFB) || \
RANGE (c, 0xFE70, 0xFE72) || \
c == 0xFE74 || \
c == 0xFE76 || \
RANGE (c, 0xFE77, 0xFEFC) || \
RANGE (c, 0xFF10, 0xFF19) || \
RANGE (c, 0xFF21, 0xFF3A) || \
RANGE (c, 0xFF41, 0xFF5A) || \
RANGE (c, 0xFF66, 0xFFBE) || \
RANGE (c, 0xFFC2, 0xFFC7) || \
RANGE (c, 0xFFCA, 0xFFCF) || \
RANGE (c, 0xFFD2, 0xFFD7) || \
RANGE (c, 0xFFDA, 0xFFDC))
/* Constants */
#define JAVA_CHAR_ERROR 0xFFC1 /* This is an illegal unicode!?! FIXME */
#define JAVA_READ_BUFFER 256
#define UEOF (unicode_t)0xffff
#endif

163
gcc/java/mangle.c Normal file
View file

@ -0,0 +1,163 @@
/* Functions related to mangling class names for the GNU compiler
for the Java(TM) language.
Copyright (C) 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC 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.
GNU CC 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, 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. */
/* Written by Per Bothner <bothner@cygnus.com> */
#include <stdio.h>
#include <string.h>
#include "config.h"
#include "jcf.h"
#include "obstack.h"
/* Assuming (NAME, LEN) is a Utf8-encoding string, calculate
the length of the string as mangled (a la g++) including Unicode escapes.
If no escapes are needed, return 0. */
int
unicode_mangling_length (name, len)
char *name;
int len;
{
unsigned char *ptr;
unsigned char *limit = (unsigned char *)name + len;
int need_escapes = 0;
int num_chars = 0;
int underscores = 0;
for (ptr = (unsigned char *) name; ptr < limit; )
{
int ch = UTF8_GET(ptr, limit);
if (ch < 0)
error ("internal error - invalid Utf8 name");
if (ch >= '0' && ch <= '9')
need_escapes += num_chars == 0;
else if (ch == '_')
underscores++;
else if ((ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z'))
need_escapes++;
num_chars++;
}
if (need_escapes)
return num_chars + 4 * (need_escapes + underscores);
else
return 0;
}
/* Assuming (NAME, LEN) is a Utf8-encoding string, emit the string
appropriately mangled (with Unicode escapes) to OBSTACK. */
void
emit_unicode_mangled_name (obstack, name, len)
struct obstack *obstack;
char *name;
{
unsigned char *ptr;
unsigned char *limit = (unsigned char *)name + len;
for (ptr = (unsigned char *) name; ptr < limit; )
{
int ch = UTF8_GET(ptr, limit);
int emit_escape;
if (ch < 0)
{
error ("internal error - bad Utf8 string");
break;
}
if (ch >= '0' && ch <= '9')
emit_escape = (ptr == (unsigned char*) name);
else
emit_escape = (ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z');
if (emit_escape)
{
char buf[6];
sprintf (buf, "_%04x", ch);
obstack_grow (obstack, buf, 5);
}
else
{
obstack_1grow (obstack, ch);
}
}
}
/* Assuming (NAME, LEN) is a Utf8-encoding string, emit the string
appropriately mangled (with Unicode escapes if needed) to OBSTACK. */
void
append_gpp_mangled_name (obstack, name, len)
struct obstack *obstack;
char *name;
int len;
{
int encoded_len = unicode_mangling_length (name, len);
int needs_escapes = encoded_len > 0;
char buf[6];
if (needs_escapes)
{
sprintf (buf, "U%d", encoded_len);
obstack_grow (obstack, buf, strlen(buf));
emit_unicode_mangled_name (obstack, name, len);
}
else
{
sprintf (buf, "%d", len);
obstack_grow (obstack, buf, strlen(buf));
obstack_grow (obstack, name, len);
}
}
/* Append the mangled name of a class named CLASSNAME onto OBSTACK. */
void
append_gpp_mangled_classtype (obstack, class_name)
struct obstack *obstack;
char *class_name;
{
char *ptr;
int qualifications = 0;
for (ptr = class_name; *ptr != '\0'; ptr++)
{
if (*ptr == '.')
qualifications++;
}
if (qualifications)
{
char buf[8];
if (qualifications >= 9)
sprintf (buf, "Q_%d_", qualifications + 1);
else
sprintf (buf, "Q%d", qualifications + 1);
obstack_grow (obstack, buf, strlen (buf));
}
for (ptr = class_name; ; ptr++)
{
if (ptr[0] == '.' || ptr[0] == '\0')
{
append_gpp_mangled_name (obstack, class_name, ptr - class_name);
if (ptr[0] == '\0')
break;
class_name = ptr + 1;
}
}
}

1162
gcc/java/parse-scan.y Normal file

File diff suppressed because it is too large Load diff

10648
gcc/java/parse.c Normal file

File diff suppressed because it is too large Load diff

599
gcc/java/parse.h Normal file
View file

@ -0,0 +1,599 @@
/* Language parser definitions for the GNU compiler for the Java(TM) language.
Copyright (C) 1997, 1998 Free Software Foundation, Inc.
Contributed by Alexandre Petit-Bianco (apbianco@cygnus.com)
This file is part of GNU CC.
GNU CC 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.
GNU CC 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, 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. */
#ifndef JV_LANG_H
#define JV_LANG_H
#include "lex.h"
/* Extern global variable declarations */
extern int java_error_count;
extern struct obstack temporary_obstack;
extern struct obstack permanent_obstack;
extern int quiet_flag;
#ifndef JC1_LITE
/* Function extern to java/ */
extern int int_fits_type_p PROTO ((tree, tree));
extern tree stabilize_reference PROTO ((tree));
#endif
/* Macros for verbose debug info */
#ifdef VERBOSE_SKELETON
#define RULE( rule ) printf ( "jv_yacc:%d: rule %s\n", lineno, rule )
#else
#define RULE( rule )
#endif
#ifdef SOURCE_FRONTEND_DEBUG
#undef SOURCE_FRONTEND_DEBUG
#define SOURCE_FRONTEND_DEBUG(X) \
{if (!quiet_flag) {printf ("* "); printf X; putchar ('\n');} }
#else
#define SOURCE_FRONTEND_DEBUG(X)
#endif
/* Macro for error recovering */
#ifdef YYDEBUG
#define RECOVERED \
{ if (!quiet_flag) {printf ("** Recovered\n");} }
#define DRECOVERED(s) \
{ if (!quiet_flag) {printf ("** Recovered (%s)\n", #s);}}
#else
#define RECOVERED
#define DRECOVERED(s)
#endif
#define DRECOVER(s) {yyerrok; DRECOVERED(s)}
#define RECOVER {yyerrok; RECOVERED}
#define YYERROR_NOW ctxp->java_error_flag = 1
#define YYNOT_TWICE if (ctxp->prevent_ese != lineno)
/* Accepted modifiers */
#define CLASS_MODIFIERS ACC_PUBLIC|ACC_ABSTRACT|ACC_FINAL
#define FIELD_MODIFIERS ACC_PUBLIC|ACC_PROTECTED|ACC_PRIVATE|ACC_FINAL| \
ACC_STATIC|ACC_TRANSIENT|ACC_VOLATILE
#define METHOD_MODIFIERS ACC_PUBLIC|ACC_PROTECTED|ACC_PRIVATE|ACC_ABSTRACT| \
ACC_STATIC|ACC_FINAL|ACC_SYNCHRONIZED|ACC_NATIVE
#define INTERFACE_MODIFIERS ACC_PUBLIC|ACC_ABSTRACT
#define INTERFACE_METHOD_MODIFIERS ACC_PUBLIC|ACC_ABSTRACT
#define INTERFACE_FIELD_MODIFIERS ACC_PUBLIC|ACC_STATIC|ACC_FINAL
/* Getting a modifier WFL */
#define MODIFIER_WFL(M) (ctxp->modifier_ctx [(M) - PUBLIC_TK])
/* Check on modifiers */
#define THIS_MODIFIER_ONLY(f, m, v, count, l) \
if ((f) & (m)) \
{ \
tree node = ctxp->modifier_ctx [v]; \
if ((l) \
&& ((EXPR_WFL_COLNO (node) > EXPR_WFL_COLNO (l)) \
|| (EXPR_WFL_LINENO (node) > EXPR_WFL_LINENO (l)))) \
l = node; \
else if (!(l)) \
l = node; \
count++; \
}
#define ABSTRACT_CHECK(flag, v, cl, s) \
if ((flag) & (v)) \
parse_error_context (cl, s " method can't be abstract");
/* Misc. */
#define exit_java_complete_class() \
{ \
pop_obstacks (); \
return; \
}
#define CLASS_OR_INTERFACE(decl, s1, s2) \
(decl ? \
((get_access_flags_from_decl (TYPE_NAME (TREE_TYPE (decl))) \
& ACC_INTERFACE) ? \
s2 : s1) : ((s1 [0]=='S'|| s1 [0]=='s') ? \
(s1 [0]=='S' ? "Supertype" : "supertype") : \
(s1 [0] > 'A' ? "Type" : "type")))
/* Pedantic warning on obsolete modifiers. Note: when cl is NULL,
flags was set artificially, such as for a interface method */
#define OBSOLETE_MODIFIER_WARNING(cl, flags, modifier, format, arg) \
{ \
if ((cl) && ((flags) & (modifier))) \
parse_warning_context (cl, \
"Discouraged redundant use of `%s' modifier " \
"in declaration of " format, \
java_accstring_lookup (modifier), arg); \
}
/* Quickly build a temporary pointer on hypothetical type NAME. */
#define BUILD_PTR_FROM_NAME(ptr, name) \
{ \
ptr = build (POINTER_TYPE, NULL_TREE); \
TYPE_NAME (ptr) = name; \
}
#define INCOMPLETE_TYPE_P(NODE) \
((TREE_CODE (NODE) == TREE_LIST) \
&& (TREE_CODE (TREE_PURPOSE (NODE)) == POINTER_TYPE) \
&& (TREE_TYPE (TREE_PURPOSE (NODE)) == NULL_TREE))
/* Set the EMIT_LINE_NOTE flag of a EXPR_WLF to 1 if debug information
are requested. Works in the context of a parser rule. */
#define JAVA_MAYBE_GENERATE_DEBUG_INFO(node) \
(debug_info_level != DINFO_LEVEL_NONE ? \
EXPR_WFL_EMIT_LINE_NOTE (node) = 1, node : node)
/* Types classification, according to the JLS, section 4.2 */
#define JFLOAT_TYPE_P(TYPE) (TREE_CODE ((TYPE)) == REAL_TYPE)
#define JINTEGRAL_TYPE_P(TYPE) ((TREE_CODE ((TYPE)) == INTEGER_TYPE) \
|| (TREE_CODE ((TYPE)) == CHAR_TYPE))
#define JNUMERIC_TYPE_P(TYPE) (JFLOAT_TYPE_P ((TYPE)) \
|| JINTEGRAL_TYPE_P ((TYPE)))
#define JPRIMITIVE_TYPE_P(TYPE) (JNUMERIC_TYPE_P ((TYPE)) \
|| (TREE_CODE ((TYPE)) == BOOLEAN_TYPE))
/* Not defined in the LRM */
#define JSTRING_TYPE_P(TYPE) ((TYPE) == string_type_node || \
(TREE_CODE (TYPE) == POINTER_TYPE && \
TREE_TYPE (op1_type) == string_type_node))
#define JREFERENCE_TYPE_P(TYPE) (TREE_CODE (TYPE) == RECORD_TYPE || \
(TREE_CODE (TYPE) == POINTER_TYPE && \
TREE_CODE (TREE_TYPE (TYPE)) == RECORD_TYPE))
/* Other predicate */
#define DECL_P(NODE) (NODE && (TREE_CODE (NODE) == PARM_DECL \
|| TREE_CODE (NODE) == VAR_DECL \
|| TREE_CODE (NODE) == FIELD_DECL))
#define TYPE_INTERFACE_P(TYPE) \
(CLASS_P (TYPE) && CLASS_INTERFACE (TYPE_NAME (TYPE)))
#define TYPE_CLASS_P(TYPE) (CLASS_P (TYPE) \
&& !CLASS_INTERFACE (TYPE_NAME (TYPE)) \
&& !TYPE_ARRAY_P (TYPE))
/* Standard error messages */
#define ERROR_CANT_CONVERT_TO_BOOLEAN(OPERATOR, NODE, TYPE) \
parse_error_context \
((OPERATOR), "Incompatible type for `%s'. Can't convert `%s' to " \
"boolean", operator_string ((NODE)), lang_printable_name ((TYPE)))
#define ERROR_CANT_CONVERT_TO_NUMERIC(OPERATOR, NODE, TYPE) \
parse_error_context \
((OPERATOR), "Incompatible type for `%s'. Can't convert `%s' to " \
"numeric type", operator_string ((NODE)), lang_printable_name ((TYPE)))
#define ERROR_CAST_NEEDED_TO_INTEGRAL(OPERATOR, NODE, TYPE) \
parse_error_context \
((OPERATOR), (JPRIMITIVE_TYPE_P (TYPE) ? \
"Incompatible type for `%s'. Explicit cast needed to convert " \
"`%s' to integral" : "Incompatible type for `%s'. Can't convert " \
"`%s' to integral"), operator_string ((NODE)), \
lang_printable_name ((TYPE)))
#define ERROR_VARIABLE_NOT_INITIALIZED(WFL, V) \
parse_error_context \
((WFL), "Variable `%s' may not have been initialized", \
IDENTIFIER_POINTER (V))
/* Definition for loop handling. This Java's own definition of a loop
body. See parse.y for documentation. It's valid once you hold a
loop's body (LOOP_EXPR_BODY) */
/* The loop main block is the one hold the condition and the loop body */
#define LOOP_EXPR_BODY_MAIN_BLOCK(NODE) TREE_OPERAND (NODE, 0)
/* And then there is the loop update block */
#define LOOP_EXPR_BODY_UPDATE_BLOCK(NODE) TREE_OPERAND (NODE, 1)
/* Inside the loop main block, there is the loop condition and the
loop body. They may be reversed if the loop being described is a
do-while loop. NOTE: if you use a WFL around the EXIT_EXPR so you
can issue debug info for it, the EXIT_EXPR will be one operand
further. */
#define LOOP_EXPR_BODY_CONDITION_EXPR(NODE, R) \
TREE_OPERAND (LOOP_EXPR_BODY_MAIN_BLOCK (NODE), (R ? 1 : 0))
/* Here is the labeled block the loop real body is encapsulated in */
#define LOOP_EXPR_BODY_LABELED_BODY(NODE, R) \
TREE_OPERAND (LOOP_EXPR_BODY_MAIN_BLOCK (NODE), (R ? 0 : 1))
/* And here is the loop's real body */
#define LOOP_EXPR_BODY_BODY_EXPR(NODE, R) \
LABELED_BLOCK_BODY (LOOP_EXPR_BODY_LABELED_BODY(NODE, R))
/* Does a loop have a label ? */
#define LOOP_HAS_LABEL_P(LOOP) \
(ctxp->current_labeled_block \
&& LABELED_BLOCK_BODY (ctxp->current_labeled_block) == (LOOP))
/* Same operation than the one performed above, but considering the
previous labeled block */
#define LOOP_HAS_LABEL_SKIP_P(LOOP) \
(ctxp->current_labeled_block \
&& TREE_CHAIN (ctxp->current_labeled_block) \
&& LABELED_BLOCK_BODY (TREE_CHAIN (ctxp->current_labeled_block)) == (LOOP))
#define PUSH_LABELED_BLOCK(B) \
{ \
TREE_CHAIN (B) = ctxp->current_labeled_block; \
ctxp->current_labeled_block = (B); \
}
#define POP_LABELED_BLOCK() \
ctxp->current_labeled_block = TREE_CHAIN (ctxp->current_labeled_block)
#define PUSH_LOOP(L) \
{ \
TREE_CHAIN (L) = ctxp->current_loop; \
ctxp->current_loop = (L); \
}
#define POP_LOOP() ctxp->current_loop = TREE_CHAIN (ctxp->current_loop)
/* Invocation modes, as returned by invocation_mode (). */
enum {
INVOKE_STATIC,
INVOKE_NONVIRTUAL,
INVOKE_SUPER,
INVOKE_INTERFACE,
INVOKE_VIRTUAL,
};
/* We need the resolution stuff only if we compile jc1 */
#ifndef JC1_LITE
/* Unresolved type identifiers handling. When we process the source
code, we blindly accept an unknown type identifier and try to
resolve it later. When an unknown type identifier is encountered
and used, we record in a struct jdep element what the incomplete
type is and what it should patch. Later, java_complete_class will
process all classes known to have unresolved type
dependencies. Within each of these classes, this routine will
process unresolved type dependencies (JDEP_TO_RESOLVE), patch what
needs to be patched in the dependent tree node (JDEP_GET_PATCH,
JDEP_APPLY_PATCH) and perform other actions dictated by the context
of the patch (JDEP_KIND). The ideas are: we patch only what needs
to be patched, and with java_complete_class called at the right
time, we will start processing incomplete function bodies tree
nodes with everything external to function's bodies already
completed, it makes things much simpler. */
enum jdep_code {
JDEP_NO_PATCH, /* Must be first */
JDEP_SUPER, /* Patch the type of one type
supertype. Requires some check
before it's done */
JDEP_FIELD, /* Patch the type of a class field */
/* JDEP_{METHOD,METHOD_RETURN,METHOD_END} to be kept in order */
JDEP_METHOD, /* Mark the beginning of the patching
of a method declaration, including
it's arguments */
JDEP_METHOD_RETURN, /* Mark the beginning of the patching
of a method declaration. Arguments
aren't patched, only the returned
type is */
JDEP_METHOD_END, /* Mark the end of the patching of a
method declaration. It indicates
that it's time to compute and
install a new signature */
JDEP_INTERFACE, /* Patch the type of a Class/interface
extension */
JDEP_VARIABLE, /* Patch the type of a variable declaration */
JDEP_PARM, /* Patch the type of a parm declaration */
JDEP_TYPE, /* Patch a random tree node type,
without the need for any specific
actions */
};
typedef struct _jdep {
#ifdef ONLY_INT_FIELDS
int kind : 8; /* Type of patch */
#else
enum jdep_code kind : 8;
#endif
int flag0 : 1; /* Some flags */
tree decl; /* Tied decl/or WFL */
tree solv; /* What to solve */
tree wfl; /* Where thing to resolve where found */
tree misc; /* Miscellaneous info (optional). */
tree *patch; /* Address of a location to patch */
struct _jdep *next; /* Linked list */
} jdep;
#define JDEP_DECL(J) ((J)->decl)
#define JDEP_DECL_WFL(J) ((J)->decl)
#define JDEP_KIND(J) ((J)->kind)
#define JDEP_SOLV(J) ((J)->solv)
#define JDEP_WFL(J) ((J)->wfl)
#define JDEP_MISC(J) ((J)->misc)
#define JDEP_CLASS(J) ((J)->class)
#define JDEP_APPLY_PATCH(J,P) (*(J)->patch = (P))
#define JDEP_GET_PATCH(J) ((J)->patch)
#define JDEP_CHAIN(J) ((J)->next)
#define JDEP_TO_RESOLVE(J) (TREE_PURPOSE ((J)->solv))
#define JDEP_RESOLVED_DECL(J) ((J)->solv ? TREE_PURPOSE ((J)->solv):NULL_TREE)
#define JDEP_RESOLVED(J, D) \
{ \
TREE_PURPOSE ((J)->solv) = D; \
TREE_VALUE ((J)->solv) = (J)->solv; \
}
#define JDEP_RESOLVED_P(J) (!(J)->solv || \
TREE_VALUE ((J)->solv) == (J)->solv)
typedef struct _jdeplist {
jdep *first;
jdep *last;
struct _jdeplist *next;
} jdeplist;
static jdeplist *reverse_jdep_list ();
#endif /* JC1_LITE */
#define CLASSD_FIRST(CD) ((CD)->first)
#define CLASSD_LAST(CD) ((CD)->last)
#define CLASSD_CHAIN(CD) ((CD)->next)
#define JDEP_INSERT(L,J) \
{ \
if (!(L)->first) \
(L)->last = (L)->first = (J); \
else \
{ \
JDEP_CHAIN ((L)->last) = (J); \
(L)->last = (J); \
} \
}
/* Insert a DECL in the current block */
#define BLOCK_CHAIN_DECL(NODE) \
{ \
TREE_CHAIN ((NODE)) = \
BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (current_function_decl)); \
BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (current_function_decl)) = (NODE); \
}
#define BLOCK_EXPR_DECLS(NODE) BLOCK_VARS(NODE)
#define BLOCK_EXPR_BODY(NODE) BLOCK_SUBBLOCKS(NODE)
#define BLOCK_EXPR_ORIGIN(NODE) BLOCK_ABSTRACT_ORIGIN(NODE)
/* Merge an other line to the source line number of a decl. Used to
remember function's end. */
#define DECL_SOURCE_LINE_MERGE(DECL,NO) DECL_SOURCE_LINE(DECL) |= (NO << 16)
/* Retrieve those two info separately. */
#define DECL_SOURCE_LINE_FIRST(DECL) (DECL_SOURCE_LINE(DECL) & 0x0000ffff)
#define DECL_SOURCE_LINE_LAST(DECL) (DECL_SOURCE_LINE(DECL) >> 16)
/* Build a WFL for expression nodes */
#define BUILD_EXPR_WFL(NODE, WFL) \
build_expr_wfl ((NODE), input_filename, EXPR_WFL_LINENO ((WFL)), \
EXPR_WFL_COLNO ((WFL)))
#define EXPR_WFL_QUALIFICATION(WFL) TREE_OPERAND ((WFL), 1)
#define QUAL_WFL(NODE) TREE_PURPOSE (NODE)
#define QUAL_RESOLUTION(NODE) TREE_VALUE (NODE)
#define QUAL_DECL_TYPE(NODE) \
(TREE_CODE (TREE_TYPE (NODE)) == POINTER_TYPE ? \
TREE_TYPE (TREE_TYPE (NODE)) : TREE_TYPE (NODE))
/* Handy macros for the walk operation */
#define COMPLETE_CHECK_OP(NODE, N) \
{ \
TREE_OPERAND ((NODE), (N)) = \
java_complete_tree (TREE_OPERAND ((NODE), (N))); \
if (TREE_OPERAND ((NODE), (N)) == error_mark_node) \
return error_mark_node; \
}
#define COMPLETE_CHECK_OP_0(NODE) COMPLETE_CHECK_OP(NODE, 0)
#define COMPLETE_CHECK_OP_1(NODE) COMPLETE_CHECK_OP(NODE, 1)
/* Parser context data structure. */
struct parser_ctxt {
char *filename; /* Current filename */
FILE *finput; /* Current file input stream */
struct parser_ctxt *next;
struct java_line *p_line, *c_line; /* Previous and current line */
java_lc elc; /* Error's line column info */
unicode_t unget_utf8_value; /* An unget utf8 value */
int ccb_indent; /* Keep track of {} indent, lexer */
int first_ccb_indent1; /* First { at ident level 1 */
int last_ccb_indent1; /* Last } at ident level 1 */
int parser_ccb_indent; /* Keep track of {} indent, parser */
int osb_number; /* Keep track of ['s */
int minus_seen; /* Integral literal overflow */
int lineno; /* Current lineno */
int java_error_flag; /* Report error when true */
/* This section is defined only if we compile jc1 */
#ifndef JC1_LITE
tree modifier_ctx [11]; /* WFL of modifiers */
tree current_class; /* Current class */
tree current_function_decl; /* Current function decl, save/restore */
JCF *current_jcf; /* CU jcf */
int prevent_ese; /* Prevent expression statement error */
int class_err; /* Flag to report certain errors */
int formal_parameter_number; /* Number of parameters found */
int interface_number; /* # itfs declared to extend an itf def */
tree package; /* Defined package ID */
tree incomplete_class; /* List of non-complete classes */
tree current_parsed_class; /* Class currently parsed */
tree class_list; /* List of classes in a CU */
jdeplist *classd_list; /* Classe dependencies in a CU */
tree non_static_initialized; /* List of non static initialized fields */
tree static_initialized; /* List of static non final initialized */
tree import_list; /* List of import */
tree import_demand_list; /* List of import on demand */
tree current_loop; /* List of the currently nested loops */
tree current_labeled_block; /* List of currently nested
labeled blocks. */
int pending_block; /* Pending block to close */
#endif /* JC1_LITE */
};
/* Functions declarations */
#ifndef JC1_LITE
static char *java_accstring_lookup PROTO ((int));
static void parse_error PROTO ((char *));
static void redefinition_error PROTO ((char *,tree, tree, tree));
static void check_modifiers PROTO ((char *, int, int));
static tree create_class PROTO ((int, tree, tree, tree));
static tree create_interface PROTO ((int, tree, tree));
static tree find_field PROTO ((tree, tree));
static tree lookup_field_wrapper PROTO ((tree, tree));
static int duplicate_declaration_error PROTO ((tree, tree, tree, tree));
static void register_fields PROTO ((int, tree, tree));
static tree parser_qualified_classname PROTO ((tree));
static int parser_check_super PROTO ((tree, tree, tree));
static int parser_check_super_interface PROTO ((tree, tree, tree));
static void check_modifiers_consistency PROTO ((int));
static tree lookup_cl PROTO ((tree));
static tree lookup_java_method2 PROTO ((tree, tree, int));
static tree method_header PROTO ((int, tree, tree, tree));
static tree method_declarator PROTO ((tree, tree));
static void parse_error_context VPROTO ((tree cl, char *msg, ...));
static void parse_warning_context VPROTO ((tree cl, char *msg, ...));
static void complete_class_report_errors PROTO ((jdep *));
static int process_imports PROTO ((void));
static void read_import_dir PROTO ((tree));
static int find_in_imports_on_demand PROTO ((tree));
static int find_in_imports PROTO ((tree));
static int check_pkg_class_access PROTO ((tree, tree));
static tree resolve_class PROTO ((tree, tree, tree));
static tree do_resolve_class PROTO ((tree, tree, tree));
static void declare_local_variables PROTO ((int, tree, tree));
static void source_start_java_method PROTO ((tree));
static void source_end_java_method PROTO ((void));
static void expand_start_java_method PROTO ((tree));
static tree find_name_in_single_imports PROTO ((tree));
static void check_abstract_method_header PROTO ((tree));
static tree lookup_java_interface_method2 PROTO ((tree, tree));
static tree resolve_expression_name PROTO ((tree));
static tree maybe_create_class_interface_decl PROTO ((tree, tree, tree));
static int check_class_interface_creation PROTO ((int, int, tree, tree, tree, tree));
static tree patch_method_invocation_stmt PROTO ((tree, tree, tree, int *));
static int breakdown_qualified PROTO ((tree *, tree *, tree));
static tree resolve_and_layout PROTO ((tree, tree));
static tree resolve_no_layout PROTO ((tree, tree));
static int identical_subpath_p PROTO ((tree, tree));
static int invocation_mode PROTO ((tree, int));
static tree refine_accessible_methods_list PROTO ((int, tree));
static tree patch_invoke PROTO ((tree, tree, tree, tree));
static tree lookup_method_invoke PROTO ((int, tree, tree, tree, tree));
static tree register_incomplete_type PROTO ((int, tree, tree, tree));
static tree obtain_incomplete_type PROTO ((tree));
static tree java_complete_tree PROTO ((tree));
static void java_complete_expand_method PROTO ((tree));
static int unresolved_type_p PROTO ((tree, tree *));
static void create_jdep_list PROTO ((struct parser_ctxt *));
static tree build_expr_block PROTO ((tree, tree));
static tree enter_block PROTO ((void));
static tree exit_block PROTO ((void));
static tree lookup_name_in_blocks PROTO ((tree));
static void maybe_absorb_scoping_blocks PROTO ((void));
static tree build_method_invocation PROTO ((tree, tree));
static tree build_assignment PROTO ((int, int, tree, tree));
static tree build_binop PROTO ((enum tree_code, int, tree, tree));
static tree patch_assignment PROTO ((tree, tree, tree ));
static tree patch_binop PROTO ((tree, tree, tree));
static tree build_unaryop PROTO ((int, int, tree));
static tree build_incdec PROTO ((int, int, tree, int));
static tree patch_unaryop PROTO ((tree, tree));
static tree build_cast PROTO ((int, tree, tree));
static tree patch_cast PROTO ((tree, tree, tree));
static int valid_ref_assignconv_cast_p PROTO ((tree, tree, int));
static int can_cast_to_p PROTO ((tree, tree));
static tree build_unresolved_array_type PROTO ((tree));
static tree build_array_ref PROTO ((int, tree, tree));
static tree patch_array_ref PROTO ((tree, tree, tree));
static tree make_qualified_name PROTO ((tree, tree, int));
static tree merge_qualified_name PROTO ((tree, tree));
static tree make_qualified_primary PROTO ((tree, tree, int));
static int resolve_qualified_expression_name PROTO ((tree, tree *, tree *, tree *));
static void qualify_ambiguous_name PROTO ((tree));
static void maybe_generate_clinit PROTO ((void));
static tree resolve_field_access PROTO ((tree, tree *, tree *));
static tree build_newarray_node PROTO ((tree, tree, int));
static tree patch_newarray PROTO ((tree));
static tree resolve_type_during_patch PROTO ((tree));
static int not_initialized_as_it_should_p PROTO ((tree));
static tree build_this PROTO ((int));
static tree build_return PROTO ((int, tree));
static tree patch_return PROTO ((tree));
static tree maybe_access_field PROTO ((tree, tree, tree));
static int complete_function_arguments PROTO ((tree));
static int check_for_static_method_reference PROTO ((tree, tree, tree, tree, tree));
static int not_accessible_p PROTO ((tree, tree, int));
static int class_in_current_package PROTO ((tree));
static tree build_if_else_statement PROTO ((int, tree, tree, tree));
static tree patch_if_else_statement PROTO ((tree));
static tree add_stmt_to_compound PROTO ((tree, tree, tree));
static tree patch_exit_expr PROTO ((tree));
static tree build_labeled_block PROTO ((int, tree, tree));
static tree generate_labeled_block PROTO (());
static tree complete_labeled_statement PROTO ((tree, tree));
static tree build_bc_statement PROTO ((int, int, tree));
static tree patch_bc_statement PROTO ((tree));
static tree patch_loop_statement PROTO ((tree));
static tree build_new_loop PROTO ((tree));
static tree build_loop_body PROTO ((int, tree, int));
static tree complete_loop_body PROTO ((int, tree, tree, int));
static tree build_debugable_stmt PROTO ((int, tree));
static tree complete_for_loop PROTO ((int, tree, tree, tree));
void safe_layout_class PROTO ((tree));
void java_complete_class PROTO ((void));
void java_check_circular_reference PROTO ((void));
void java_check_final PROTO ((void));
void java_check_methods PROTO ((void));
void java_layout_classes PROTO ((void));
tree java_method_add_stmt PROTO ((tree, tree));
char *java_get_line_col PROTO ((char *, int, int));
#endif /* JC1_LITE */
/* Always in use, no matter what you compile */
void java_push_parser_context PROTO ((void));
void java_init_lex PROTO ((void));
int yyparse PROTO ((void));
int yylex ();
void yyerror PROTO ((char *));
#endif

8035
gcc/java/parse.y Normal file

File diff suppressed because it is too large Load diff

785
gcc/java/typeck.c Normal file
View file

@ -0,0 +1,785 @@
/* Handle types for the GNU compiler for the Java(TM) language.
Copyright (C) 1996 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC 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.
GNU CC 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, 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. */
/* Written by Per Bothner <bothner@cygnus.com> */
#include "config.h"
#include "tree.h"
#include "obstack.h"
#include "java-tree.h"
#include "jcf.h"
#include "convert.h"
tree * type_map;
extern struct obstack permanent_obstack;
/* Set the type of the local variable with index SLOT to TYPE. */
void
set_local_type (slot, type)
int slot;
tree type;
{
int max_locals = DECL_MAX_LOCALS(current_function_decl);
int nslots = TYPE_IS_WIDE (type) ? 2 : 1;
if (slot < 0 || slot + nslots - 1 >= max_locals)
fatal ("invalid local variable index");
type_map[slot] = type;
while (--nslots > 0)
type_map[++slot] = void_type_node;
}
extern tree convert_to_integer (tree type, tree expr);
extern tree convert_to_real (tree type, tree expr);
extern tree convert_to_pointer (tree type, tree expr);
/* Create an expression whose value is that of EXPR,
converted to type TYPE. The TREE_TYPE of the value
is always TYPE. This function implements all reasonable
conversions; callers should filter out those that are
not permitted by the language being compiled. */
tree
convert (type, expr)
tree type, expr;
{
register enum tree_code code = TREE_CODE (type);
if (type == TREE_TYPE (expr)
|| TREE_CODE (expr) == ERROR_MARK)
return expr;
if (TREE_CODE (TREE_TYPE (expr)) == ERROR_MARK)
return error_mark_node;
if (code == BOOLEAN_TYPE)
return fold (convert_to_boolean (type, expr));
if (code == INTEGER_TYPE)
return fold (convert_to_integer (type, expr));
if (code == REAL_TYPE)
return fold (convert_to_real (type, expr));
if (code == CHAR_TYPE)
return fold (convert_to_char (type, expr));
if (code == POINTER_TYPE)
return fold (convert_to_pointer (type, expr));
error ("conversion to non-scalar type requested");
return error_mark_node;
}
tree
convert_to_char (type, expr)
tree type, expr;
{
return build1 (NOP_EXPR, type, expr);
}
tree
convert_to_boolean (type, expr)
tree type, expr;
{
return build1 (NOP_EXPR, type, expr);
}
/* Print an error message for invalid use of an incomplete type.
VALUE is the expression that was used (or 0 if that isn't known)
and TYPE is the type that was invalid. */
void
incomplete_type_error (value, type)
tree value;
tree type;
{
error ("internal error - use of undefined type");
}
/* Return a data type that has machine mode MODE.
If the mode is an integer,
then UNSIGNEDP selects between signed and unsigned types. */
tree
type_for_mode (mode, unsignedp)
enum machine_mode mode;
int unsignedp;
{
if (mode == TYPE_MODE (int_type_node))
return unsignedp ? unsigned_int_type_node : int_type_node;
if (mode == TYPE_MODE (long_type_node))
return unsignedp ? unsigned_long_type_node : long_type_node;
if (mode == TYPE_MODE (short_type_node))
return unsignedp ? unsigned_short_type_node : short_type_node;
if (mode == TYPE_MODE (byte_type_node))
return unsignedp ? unsigned_byte_type_node : byte_type_node;
if (mode == TYPE_MODE (float_type_node))
return float_type_node;
if (mode == TYPE_MODE (double_type_node))
return double_type_node;
#if 0
if (mode == TYPE_MODE (build_pointer_type (char_type_node)))
return build_pointer_type (char_type_node);
if (mode == TYPE_MODE (build_pointer_type (integer_type_node)))
return build_pointer_type (integer_type_node);
#endif
return 0;
}
/* Return an integer type with BITS bits of precision,
that is unsigned if UNSIGNEDP is nonzero, otherwise signed. */
tree
type_for_size (bits, unsignedp)
unsigned bits;
int unsignedp;
{
if (bits <= TYPE_PRECISION (byte_type_node))
return unsignedp ? unsigned_byte_type_node : byte_type_node;
if (bits <= TYPE_PRECISION (short_type_node))
return unsignedp ? unsigned_short_type_node : short_type_node;
if (bits <= TYPE_PRECISION (int_type_node))
return unsignedp ? unsigned_int_type_node : int_type_node;
if (bits <= TYPE_PRECISION (long_type_node))
return unsignedp ? unsigned_long_type_node : long_type_node;
return 0;
}
/* Return a type the same as TYPE except unsigned or
signed according to UNSIGNEDP. */
tree
signed_or_unsigned_type (unsignedp, type)
int unsignedp;
tree type;
{
if (! INTEGRAL_TYPE_P (type))
return type;
if (TYPE_PRECISION (type) == TYPE_PRECISION (int_type_node))
return unsignedp ? unsigned_int_type_node : int_type_node;
if (TYPE_PRECISION (type) == TYPE_PRECISION (byte_type_node))
return unsignedp ? unsigned_byte_type_node : byte_type_node;
if (TYPE_PRECISION (type) == TYPE_PRECISION (short_type_node))
return unsignedp ? unsigned_short_type_node : short_type_node;
if (TYPE_PRECISION (type) == TYPE_PRECISION (long_type_node))
return unsignedp ? unsigned_long_type_node : long_type_node;
return type;
}
/* Return a signed type the same as TYPE in other respects. */
tree
signed_type (type)
tree type;
{
return signed_or_unsigned_type (0, type);
}
/* Return an unsigned type the same as TYPE in other respects. */
tree
unsigned_type (type)
tree type;
{
return signed_or_unsigned_type (1, type);
}
/* Mark EXP saying that we need to be able to take the
address of it; it should not be allocated in a register.
Value is 1 if successful. */
int
mark_addressable (exp)
tree exp;
{
register tree x = exp;
while (1)
switch (TREE_CODE (x))
{
case ADDR_EXPR:
case COMPONENT_REF:
case ARRAY_REF:
case REALPART_EXPR:
case IMAGPART_EXPR:
x = TREE_OPERAND (x, 0);
break;
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
case COMPOUND_EXPR:
x = TREE_OPERAND (x, 1);
break;
case COND_EXPR:
return mark_addressable (TREE_OPERAND (x, 1))
& mark_addressable (TREE_OPERAND (x, 2));
case CONSTRUCTOR:
TREE_ADDRESSABLE (x) = 1;
return 1;
case INDIRECT_REF:
/* We sometimes add a cast *(TYPE*)&FOO to handle type and mode
incompatibility problems. Handle this case by marking FOO. */
if (TREE_CODE (TREE_OPERAND (x, 0)) == NOP_EXPR
&& TREE_CODE (TREE_OPERAND (TREE_OPERAND (x, 0), 0)) == ADDR_EXPR)
{
x = TREE_OPERAND (TREE_OPERAND (x, 0), 0);
break;
}
if (TREE_CODE (TREE_OPERAND (x, 0)) == ADDR_EXPR)
{
x = TREE_OPERAND (x, 0);
break;
}
return 1;
case VAR_DECL:
case CONST_DECL:
case PARM_DECL:
case RESULT_DECL:
case FUNCTION_DECL:
TREE_ADDRESSABLE (x) = 1;
#if 0 /* poplevel deals with this now. */
if (DECL_CONTEXT (x) == 0)
TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (x)) = 1;
#endif
/* drops through */
default:
return 1;
}
}
/* Thorough checking of the arrayness of TYPE. */
int
is_array_type_p (type)
tree type;
{
return TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE
&& TYPE_ARRAY_P (TREE_TYPE (type));
}
/* Return the length of a Java array type.
Return -1 if the length is unknown or non-constant. */
HOST_WIDE_INT
java_array_type_length (array_type)
tree array_type;
{
tree arfld;
if (TREE_CODE (array_type) == POINTER_TYPE)
array_type = TREE_TYPE (array_type);
arfld = TREE_CHAIN (TREE_CHAIN (TYPE_FIELDS (array_type)));
if (arfld != NULL_TREE)
{
tree index_type = TYPE_DOMAIN (TREE_TYPE (arfld));
tree high = TYPE_MAX_VALUE (index_type);
if (TREE_CODE (high) == INTEGER_CST)
return TREE_INT_CST_LOW (high) + 1;
}
return -1;
}
tree
build_prim_array_type (element_type, length)
tree element_type;
HOST_WIDE_INT length;
{
tree max_index = build_int_2 (length - 1, 0);
TREE_TYPE (max_index) = sizetype;
return build_array_type (element_type, build_index_type (max_index));
}
/* Return a Java array type with a given ELEMENT_TYPE and LENGTH.
These are hashed (shared) using IDENTIFIER_SIGNATURE_TYPE.
The LENGTH is -1 if the length is unknown. */
tree
build_java_array_type (element_type, length)
tree element_type;
HOST_WIDE_INT length;
{
tree sig, t, fld;
char buf[12];
tree elsig = build_java_signature (element_type);
tree el_name = element_type;
sprintf (buf, length >= 0 ? "[%d" : "[", length);
sig = ident_subst (IDENTIFIER_POINTER (elsig), IDENTIFIER_LENGTH (elsig),
buf, 0, 0, "");
t = IDENTIFIER_SIGNATURE_TYPE (sig);
if (t != NULL_TREE)
return t;
t = make_class ();
IDENTIFIER_SIGNATURE_TYPE (sig) = t;
TYPE_ARRAY_P (t) = 1;
if (TREE_CODE (el_name) == POINTER_TYPE)
el_name = TREE_TYPE (el_name);
el_name = TYPE_NAME (el_name);
if (TREE_CODE (el_name) == TYPE_DECL)
el_name = DECL_NAME (el_name);
TYPE_NAME (t) = identifier_subst (el_name, "", '.', '.', "[]");
set_java_signature (t, sig);
set_super_info (0, t, object_type_node, 0);
TYPE_ARRAY_ELEMENT (t) = element_type;
/* Add length pseudo-field. */
push_obstacks (&permanent_obstack, &permanent_obstack);
fld = build_decl (FIELD_DECL, get_identifier ("length"), int_type_node);
TYPE_FIELDS (t) = fld;
DECL_CONTEXT (fld) = t;
FIELD_PUBLIC (fld) = 1;
FIELD_FINAL (fld) = 1;
if (length >= 0)
{
tree atype = build_prim_array_type (element_type, length);
tree arfld = build_decl (FIELD_DECL, get_identifier ("data"), atype);
DECL_CONTEXT (arfld) = t;
TREE_CHAIN (fld) = arfld;
}
else
TYPE_ALIGN (t) = TYPE_ALIGN (element_type);
pop_obstacks ();
layout_class (t);
return t;
}
/* Promote TYPE to the type actually used for fields and parameters. */
tree
promote_type (type)
tree type;
{
switch (TREE_CODE (type))
{
case RECORD_TYPE:
return build_pointer_type (CLASS_TO_HANDLE_TYPE (type));
case BOOLEAN_TYPE:
if (type == boolean_type_node)
return promoted_boolean_type_node;
goto handle_int;
case CHAR_TYPE:
if (type == char_type_node)
return promoted_char_type_node;
goto handle_int;
case INTEGER_TYPE:
handle_int:
if (TYPE_PRECISION (type) < TYPE_PRECISION (int_type_node))
{
if (type == short_type_node)
return promoted_short_type_node;
if (type == byte_type_node)
return promoted_byte_type_node;
return int_type_node;
}
/* ... else fall through ... */
default:
return type;
}
}
/* Parse a signature string, starting at *PTR and ending at LIMIT.
Return the seen TREE_TYPE, updating *PTR. */
static tree
parse_signature_type (ptr, limit)
const unsigned char **ptr, *limit;
{
if ((*ptr) >= limit)
fatal ("bad signature string");
switch (*(*ptr))
{
case 'B': (*ptr)++; return byte_type_node;
case 'C': (*ptr)++; return char_type_node;
case 'D': (*ptr)++; return double_type_node;
case 'F': (*ptr)++; return float_type_node;
case 'S': (*ptr)++; return short_type_node;
case 'I': (*ptr)++; return int_type_node;
case 'J': (*ptr)++; return long_type_node;
case 'Z': (*ptr)++; return boolean_type_node;
case 'V': (*ptr)++; return void_type_node;
case '[':
for ((*ptr)++; (*ptr) < limit && isdigit (**ptr); ) (*ptr)++;
{
tree element_type = parse_signature_type (ptr, limit);
if (TREE_CODE (element_type) == RECORD_TYPE)
element_type = promote_type (element_type);
return build_java_array_type (element_type, -1);
}
case 'L':
{
const unsigned char *start = ++(*ptr);
register const unsigned char *str = start;
for ( ; ; str++)
{
if (str >= limit)
fatal ("bad signature string");
if (*str == ';')
break;
}
*ptr = str+1;
return lookup_class (unmangle_classname (start, str - start));
}
default:
fatal ("unrecognized signature string");
}
}
/* Parse a Java "mangled" signature string, starting at SIG_STRING,
and SIG_LENGTH bytes long.
Return a gcc type node. */
tree
parse_signature_string (sig_string, sig_length)
const unsigned char *sig_string;
int sig_length;
{
tree result_type;
const unsigned char *str = sig_string;
const unsigned char *limit = str + sig_length;
push_obstacks (&permanent_obstack, &permanent_obstack);
if (str < limit && str[0] == '(')
{
tree argtype_list = NULL_TREE;
str++;
while (str < limit && str[0] != ')')
{
tree argtype = promote_type (parse_signature_type (&str, limit));
argtype_list = tree_cons (NULL_TREE, argtype, argtype_list);
}
if (str++, str >= limit)
fatal ("bad signature string");
result_type = promote_type (parse_signature_type (&str, limit));
result_type = build_function_type (result_type,
nreverse (argtype_list));
}
else
result_type = parse_signature_type (&str, limit);
if (str != limit)
error ("junk at end of signature string");
pop_obstacks ();
return result_type;
}
/* Convert a signature to its type.
* Uses IDENTIFIER_SIGNATURE_TYPE as a cache (except for primitive types).
*/
tree
get_type_from_signature (tree signature)
{
unsigned char *sig = (unsigned char *) IDENTIFIER_POINTER (signature);
int len = IDENTIFIER_LENGTH (signature);
tree type;
/* Primitive types aren't cached. */
if (len <= 1)
return parse_signature_string (sig, len);
type = IDENTIFIER_SIGNATURE_TYPE (signature);
if (type == NULL_TREE)
{
type = parse_signature_string (sig, len);
IDENTIFIER_SIGNATURE_TYPE (signature) = type;
}
return type;
}
/* Return the signature string for the arguments of method type TYPE. */
tree
build_java_argument_signature (type)
tree type;
{
extern struct obstack temporary_obstack;
tree sig = TYPE_ARGUMENT_SIGNATURE (type);
if (sig == NULL_TREE)
{
tree args = TYPE_ARG_TYPES (type);
if (TREE_CODE (type) == METHOD_TYPE)
args = TREE_CHAIN (args); /* Skip "this" argument. */
for (; args != NULL_TREE; args = TREE_CHAIN (args))
{
tree t = build_java_signature (TREE_VALUE (args));
obstack_grow (&temporary_obstack,
IDENTIFIER_POINTER (t), IDENTIFIER_LENGTH (t));
}
obstack_1grow (&temporary_obstack, '\0');
sig = get_identifier (obstack_base (&temporary_obstack));
TYPE_ARGUMENT_SIGNATURE (type) = sig;
obstack_free (&temporary_obstack, obstack_base (&temporary_obstack));
}
return sig;
}
/* Return the signature of the given TYPE. */
tree
build_java_signature (type)
tree type;
{
tree sig, t;
push_obstacks (&permanent_obstack, &permanent_obstack);
while (TREE_CODE (type) == POINTER_TYPE)
type = TREE_TYPE (type);
if (TYPE_LANG_SPECIFIC (type) == NULL)
{
TYPE_LANG_SPECIFIC (type) = (struct lang_type *)
perm_calloc (1, sizeof (struct lang_type));
}
sig = TYPE_LANG_SPECIFIC (type)->signature;
if (sig == NULL_TREE)
{
char sg[2];
switch (TREE_CODE (type))
{
case BOOLEAN_TYPE: sg[0] = 'Z'; goto native;
case CHAR_TYPE: sg[0] = 'C'; goto native;
case VOID_TYPE: sg[0] = 'V'; goto native;
case INTEGER_TYPE:
switch (TYPE_PRECISION (type))
{
case 8: sg[0] = 'B'; goto native;
case 16: sg[0] = 'S'; goto native;
case 32: sg[0] = 'I'; goto native;
case 64: sg[0] = 'J'; goto native;
default: goto bad_type;
}
case REAL_TYPE:
switch (TYPE_PRECISION (type))
{
case 32: sg[0] = 'F'; goto native;
case 64: sg[0] = 'D'; goto native;
default: goto bad_type;
}
native:
sg[1] = 0;
sig = get_identifier (sg);
break;
case RECORD_TYPE:
if (TYPE_ARRAY_P (type))
{
t = build_java_signature (TYPE_ARRAY_ELEMENT (type));
sig = ident_subst (IDENTIFIER_POINTER (t), IDENTIFIER_LENGTH (t),
"[", 0, 0, "");
}
else
{
t = DECL_NAME (TYPE_NAME (type));
sig = ident_subst (IDENTIFIER_POINTER (t), IDENTIFIER_LENGTH (t),
"L", '.', '/', ";");
}
break;
case METHOD_TYPE:
case FUNCTION_TYPE:
{
extern struct obstack temporary_obstack;
sig = build_java_argument_signature (type);
obstack_1grow (&temporary_obstack, '(');
obstack_grow (&temporary_obstack,
IDENTIFIER_POINTER (sig), IDENTIFIER_LENGTH (sig));
obstack_1grow (&temporary_obstack, ')');
t = build_java_signature (TREE_TYPE (type));
obstack_grow0 (&temporary_obstack,
IDENTIFIER_POINTER (t), IDENTIFIER_LENGTH (t));
sig = get_identifier (obstack_base (&temporary_obstack));
obstack_free (&temporary_obstack,
obstack_base (&temporary_obstack));
}
break;
bad_type:
default:
fatal ("internal error - build_java_signature passed invalid type");
}
TYPE_LANG_SPECIFIC (type)->signature = sig;
}
pop_obstacks ();
return sig;
}
/* Save signature string SIG (an IDENTIFIER_NODE) in TYPE for future use. */
void
set_java_signature (type, sig)
tree type;
tree sig;
{
tree old_sig;
while (TREE_CODE (type) == POINTER_TYPE)
type = TREE_TYPE (type);
if (TYPE_LANG_SPECIFIC (type) == NULL)
{
TYPE_LANG_SPECIFIC (type) = (struct lang_type *)
perm_calloc (1, sizeof (struct lang_type));
}
old_sig = TYPE_LANG_SPECIFIC (type)->signature;
if (old_sig != NULL_TREE && old_sig != sig)
fatal ("internal error - set_java_signature");
TYPE_LANG_SPECIFIC (type)->signature = sig;
#if 0 /* careful about METHOD_TYPE */
if (IDENTIFIER_SIGNATURE_TYPE (sig) == NULL_TREE && TREE_PERMANENT (type))
IDENTIFIER_SIGNATURE_TYPE (sig) = type;
#endif
}
/* Search in class CLAS (and its superclasses) for a method
matching METHOD_NAME and argument signature METHOD_SIGNATURE.
Return a FUNCTION_DECL on success, or NULL_TREE if none found.
(Contrast lookup_java_method, which takes into account return type.) */
tree
lookup_argument_method (clas, method_name, method_signature)
tree clas, method_name, method_signature;
{
tree method;
while (clas != NULL_TREE)
{
for (method = TYPE_METHODS (clas);
method != NULL_TREE; method = TREE_CHAIN (method))
{
tree method_sig = build_java_argument_signature (TREE_TYPE (method));
if (DECL_NAME (method) == method_name && method_sig == method_signature)
return method;
}
clas = CLASSTYPE_SUPER (clas);
}
return NULL_TREE;
}
/* Search in class CLAS (and its superclasses) for a method
matching METHOD_NAME and signature METHOD_SIGNATURE.
Return a FUNCTION_DECL on success, or NULL_TREE if none found.
(Contrast lookup_argument_method, which ignores return type.) */
tree
lookup_java_method (clas, method_name, method_signature)
tree clas, method_name, method_signature;
{
tree method;
while (clas != NULL_TREE)
{
for (method = TYPE_METHODS (clas);
method != NULL_TREE; method = TREE_CHAIN (method))
{
tree method_sig = build_java_signature (TREE_TYPE (method));
if (DECL_NAME (method) == method_name && method_sig == method_signature)
return method;
}
clas = CLASSTYPE_SUPER (clas);
}
return NULL_TREE;
}
/* Search in class CLAS (and its superclasses) for methods matching
METHOD_NAME and METHOD_SIGNATURE. Return a list of FUNCTION_DECLs.
When called from here, build_java_signature doesn't take the
returned type into account. */
tree
match_java_method (clas, method_name, method_signature)
tree clas, method_name, method_signature;
{
tree method;
tree list = NULL_TREE;
while (clas != NULL_TREE)
{
for (method = TYPE_METHODS (clas);
method != NULL_TREE; method = TREE_CHAIN (method))
{
tree method_sig = build_java_argument_signature (TREE_TYPE (method));
if (DECL_NAME (method) == method_name
&& method_sig == method_signature)
list = tree_cons (NULL_TREE, method, list);
}
clas = CLASSTYPE_SUPER (clas);
}
return list;
}
/* Search in class CLAS for a constructor matching METHOD_SIGNATURE.
Return a FUNCTION_DECL on success, or NULL_TREE if none found. */
tree
lookup_java_constructor (clas, method_signature)
tree clas, method_signature;
{
tree method = TYPE_METHODS (clas);
for ( ; method != NULL_TREE; method = TREE_CHAIN (method))
{
tree method_sig = build_java_signature (TREE_TYPE (method));
if (DECL_CONSTRUCTOR_P (method) && method_sig == method_signature)
return method;
}
return NULL_TREE;
}
/* Return a type which is the Binary Numeric Promotion of the pair T1,
T2 and convert EXP1 and/or EXP2. See 5.6.2 Binary Numeric
Promotion. It assumes that both T1 and T2 are elligible to BNP. */
tree
binary_numeric_promotion (t1, t2, exp1, exp2)
tree t1;
tree t2;
tree *exp1;
tree *exp2;
{
if (t1 == double_type_node || t2 == double_type_node)
{
if (t1 != double_type_node)
*exp1 = convert (double_type_node, *exp1);
if (t2 != double_type_node)
*exp2 = convert (double_type_node, *exp2);
return double_type_node;
}
if (t1 == float_type_node || t2 == float_type_node)
{
if (t1 != float_type_node)
*exp1 = convert (float_type_node, *exp1);
if (t2 != float_type_node)
*exp2 = convert (float_type_node, *exp2);
return float_type_node;
}
if (t1 == long_type_node || t2 == long_type_node)
{
if (t1 != long_type_node)
*exp1 = convert (long_type_node, *exp1);
if (t2 != long_type_node)
*exp2 = convert (long_type_node, *exp2);
return long_type_node;
}
if (t1 != int_type_node)
*exp1 = convert (int_type_node, *exp1);
if (t2 != int_type_node)
*exp2 = convert (int_type_node, *exp2);
return int_type_node;
}

1239
gcc/java/verify.c Normal file

File diff suppressed because it is too large Load diff

350
gcc/java/zextract.c Normal file
View file

@ -0,0 +1,350 @@
/* Handle a .class file embedded in a .zip archive.
This extracts a member from a .zip file, but does not handle
uncompression (since that is not needed for classes.zip).
Copyright (C) 1996 Free Software Foundation, Inc.
This program 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.
This program 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, 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. */
/* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
#include "zipfile.h"
/* This stuff is partly based on the 28 August 1994 public release of the
Info-ZIP group's portable UnZip zipfile-extraction program (and related
utilities). */
#include <stdio.h>
#ifdef __STDC__
#include <stdlib.h>
#endif
#include <errno.h> /* used in mapname() */
/*************/
/* Defines */
/*************/
#define UNZIP
#define UNZIP_VERSION 20 /* compatible with PKUNZIP 2.0 */
#define VMS_UNZIP_VERSION 42 /* if OS-needed-to-extract is VMS: can do */
#define ZSUFX ".zip"
#define CENTRAL_HDR_SIG "\113\001\002" /* the infamous "PK" signature */
#define LOCAL_HDR_SIG "\113\003\004" /* bytes, sans "P" (so unzip */
#define END_CENTRAL_SIG "\113\005\006" /* executable not mistaken for */
#define EXTD_LOCAL_SIG "\113\007\010" /* zipfile itself) */
#define STORED 0 /* compression methods */
#define SHRUNK 1
#define REDUCED1 2
#define REDUCED2 3
#define REDUCED3 4
#define REDUCED4 5
#define IMPLODED 6
#define TOKENIZED 7
#define DEFLATED 8
#define NUM_METHODS 9 /* index of last method + 1 */
/* don't forget to update list_files() appropriately if NUM_METHODS changes */
#define PK_OK 0 /* no error */
#define PK_COOL 0 /* no error */
#define PK_GNARLY 0 /* no error */
#define PK_WARN 1 /* warning error */
#define PK_ERR 2 /* error in zipfile */
#define PK_BADERR 3 /* severe error in zipfile */
#define PK_MEM 4 /* insufficient memory */
#define PK_MEM2 5 /* insufficient memory */
#define PK_MEM3 6 /* insufficient memory */
#define PK_MEM4 7 /* insufficient memory */
#define PK_MEM5 8 /* insufficient memory */
#define PK_NOZIP 9 /* zipfile not found */
#define PK_PARAM 10 /* bad or illegal parameters specified */
#define PK_FIND 11 /* no files found */
#define PK_DISK 50 /* disk full */
#define PK_EOF 51 /* unexpected EOF */
/*---------------------------------------------------------------------------
True sizes of the various headers, as defined by PKWARE--so it is not
likely that these will ever change. But if they do, make sure both these
defines AND the typedefs below get updated accordingly.
---------------------------------------------------------------------------*/
#define LREC_SIZE 26 /* lengths of local file headers, central */
#define CREC_SIZE 42 /* directory headers, and the end-of- */
#define ECREC_SIZE 18 /* central-dir record, respectively */
#ifndef SEEK_SET
# define SEEK_SET 0
# define SEEK_CUR 1
# define SEEK_END 2
#endif
/**************/
/* Typedefs */
/**************/
typedef char boolean;
typedef unsigned char uch; /* code assumes unsigned bytes; these type- */
typedef unsigned short ush; /* defs replace byte/UWORD/ULONG (which are */
typedef unsigned long ulg; /* predefined on some systems) & match zip */
/*---------------------------------------------------------------------------
Zipfile layout declarations. If these headers ever change, make sure the
xxREC_SIZE defines (above) change with them!
---------------------------------------------------------------------------*/
typedef uch local_byte_hdr[ LREC_SIZE ];
# define L_VERSION_NEEDED_TO_EXTRACT_0 0
# define L_VERSION_NEEDED_TO_EXTRACT_1 1
# define L_GENERAL_PURPOSE_BIT_FLAG 2
# define L_COMPRESSION_METHOD 4
# define L_LAST_MOD_FILE_TIME 6
# define L_LAST_MOD_FILE_DATE 8
# define L_CRC32 10
# define L_COMPRESSED_SIZE 14
# define L_UNCOMPRESSED_SIZE 18
# define L_FILENAME_LENGTH 22
# define L_EXTRA_FIELD_LENGTH 24
typedef uch cdir_byte_hdr[ CREC_SIZE ];
# define C_VERSION_MADE_BY_0 0
# define C_VERSION_MADE_BY_1 1
# define C_VERSION_NEEDED_TO_EXTRACT_0 2
# define C_VERSION_NEEDED_TO_EXTRACT_1 3
# define C_GENERAL_PURPOSE_BIT_FLAG 4
# define C_COMPRESSION_METHOD 6
# define C_LAST_MOD_FILE_TIME 8
# define C_LAST_MOD_FILE_DATE 10
# define C_CRC32 12
# define C_COMPRESSED_SIZE 16
# define C_UNCOMPRESSED_SIZE 20
# define C_FILENAME_LENGTH 24
# define C_EXTRA_FIELD_LENGTH 26
# define C_FILE_COMMENT_LENGTH 28
# define C_DISK_NUMBER_START 30
# define C_INTERNAL_FILE_ATTRIBUTES 32
# define C_EXTERNAL_FILE_ATTRIBUTES 34
# define C_RELATIVE_OFFSET_LOCAL_HEADER 38
typedef uch ec_byte_rec[ ECREC_SIZE+4 ];
/* define SIGNATURE 0 space-holder only */
# define NUMBER_THIS_DISK 4
# define NUM_DISK_WITH_START_CENTRAL_DIR 6
# define NUM_ENTRIES_CENTRL_DIR_THS_DISK 8
# define TOTAL_ENTRIES_CENTRAL_DIR 10
# define SIZE_CENTRAL_DIRECTORY 12
# define OFFSET_START_CENTRAL_DIRECTORY 16
# define ZIPFILE_COMMENT_LENGTH 20
typedef struct local_file_header { /* LOCAL */
uch version_needed_to_extract[2];
ush general_purpose_bit_flag;
ush compression_method;
ush last_mod_file_time;
ush last_mod_file_date;
ulg crc32;
ulg csize;
ulg ucsize;
ush filename_length;
ush extra_field_length;
} local_file_hdr;
typedef struct central_directory_file_header { /* CENTRAL */
uch version_made_by[2];
uch version_needed_to_extract[2];
ush general_purpose_bit_flag;
ush compression_method;
ush last_mod_file_time;
ush last_mod_file_date;
ulg crc32;
ulg csize;
ulg ucsize;
ush filename_length;
ush extra_field_length;
ush file_comment_length;
ush disk_number_start;
ush internal_file_attributes;
ulg external_file_attributes;
ulg relative_offset_local_header;
} cdir_file_hdr;
typedef struct end_central_dir_record { /* END CENTRAL */
ush number_this_disk;
ush num_disk_with_start_central_dir;
ush num_entries_centrl_dir_ths_disk;
ush total_entries_central_dir;
ulg size_central_directory;
ulg offset_start_central_directory;
ush zipfile_comment_length;
} ecdir_rec;
/************/
/* Macros */
/************/
#ifndef MAX
# define MAX(a,b) ((a) > (b) ? (a) : (b))
#endif
#ifndef MIN
# define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
/***********************/
/* Function makeword() */
/***********************/
static ush makeword(b)
uch *b;
{
/*
* Convert Intel style 'short' integer to non-Intel non-16-bit
* host format. This routine also takes care of byte-ordering.
*/
return (ush)((b[1] << 8) | b[0]);
}
/***********************/
/* Function makelong() */
/***********************/
static ulg makelong(sig)
uch *sig;
{
/*
* Convert intel style 'long' variable to non-Intel non-16-bit
* host format. This routine also takes care of byte-ordering.
*/
return (((ulg)sig[3]) << 24)
+ (((ulg)sig[2]) << 16)
+ (((ulg)sig[1]) << 8)
+ ((ulg)sig[0]);
}
int
read_zip_archive (zipf)
register ZipFile *zipf;
{
int i;
int dir_last_pad;
char *dir_ptr;
char buffer[100];
zipf->size = lseek (zipf->fd, 0L, SEEK_END);
if (zipf->size < (ECREC_SIZE+4) || lseek (zipf->fd, (long)(-(ECREC_SIZE+4)), SEEK_CUR) <= 0)
return -1;
if (read (zipf->fd, buffer, ECREC_SIZE+4) != ECREC_SIZE+4)
return -2;
zipf->count = makeword(&buffer[TOTAL_ENTRIES_CENTRAL_DIR]);
zipf->dir_size = makelong(&buffer[SIZE_CENTRAL_DIRECTORY]);
#define ALLOC malloc
/* Allocate 1 more to allow appending '\0' to last filename. */
zipf->central_directory = ALLOC (zipf->dir_size+1);
if (lseek (zipf->fd, -(zipf->dir_size+ECREC_SIZE+4), SEEK_CUR) < 0)
return -2;
if (read (zipf->fd, zipf->central_directory, zipf->dir_size) < 0)
return -2;
#ifdef TEST
printf ("number_this_disk = %d\n", makeword(&buffer[NUMBER_THIS_DISK]));
printf ("num_disk_with_start_central_dir = %d\n", makeword(&buffer[NUM_DISK_WITH_START_CENTRAL_DIR]));
printf ("num_entries_centrl_dir_ths_disk = %d\n",
makeword(&buffer[NUM_ENTRIES_CENTRL_DIR_THS_DISK]));
printf ("total_entries_central_dir = %d\n",
makeword(&buffer[TOTAL_ENTRIES_CENTRAL_DIR]));
printf ("size_central_directory = %d\n",
makelong(&buffer[SIZE_CENTRAL_DIRECTORY]));
printf ("offset_start_central_directory = %d\n",
makelong(&buffer[OFFSET_START_CENTRAL_DIRECTORY]));
printf ("zipfile_comment_length = %d\n",
makeword(&buffer[ZIPFILE_COMMENT_LENGTH]));
#endif
dir_last_pad = 0;
dir_ptr = zipf->central_directory;
for (i = 0; i < zipf->count; i++)
{
ZipDirectory *zipd = (ZipDirectory*)(dir_ptr + dir_last_pad);
long uncompressed_size = makelong (&dir_ptr[4+C_UNCOMPRESSED_SIZE]);
long filename_length = makeword (&dir_ptr[4+C_FILENAME_LENGTH]);
long extra_field_length = makeword (&dir_ptr[4+C_EXTRA_FIELD_LENGTH]);
long file_comment_length = makeword (&dir_ptr[4+C_FILE_COMMENT_LENGTH]);
int unpadded_direntry_length;
if ((dir_ptr-zipf->central_directory)+filename_length+CREC_SIZE+4>zipf->dir_size)
return -1;
zipd->filename_length = filename_length;
zipd->size = uncompressed_size;
#ifdef __GNUC__
#define DIR_ALIGN __alignof__(ZipDirectory)
#else
#define DIR_ALIGN sizeof(long)
#endif
zipd->filestart = makelong (&dir_ptr[4+C_RELATIVE_OFFSET_LOCAL_HEADER])
+ (LREC_SIZE+4) + filename_length + file_comment_length +
+ (extra_field_length ? extra_field_length+4 : 0);
/* About the last term of the expression above. Should the same
apply if file_comment_length is not zero ? I've never seen
the comment field uses so far. FIXME. */
zipd->filename_offset = CREC_SIZE+4 - dir_last_pad;
unpadded_direntry_length
= zipd->filename_offset + zipd->filename_length + extra_field_length;
zipd->direntry_size =
((unpadded_direntry_length + DIR_ALIGN) / DIR_ALIGN) * DIR_ALIGN;
dir_last_pad = zipd->direntry_size - unpadded_direntry_length;
dir_ptr = (char*)zipd + unpadded_direntry_length;
*dir_ptr = '\0';
}
return 0;
}
#ifdef TEST
main ()
{
ZipFile zipf[1];
ZipDirectory *zipd;
int i;
zipf->fd = 0;
i = read_zip_archive (zipf);
if (i)
{
fprintf (stderr, "Bad zip file.\n");
exit (i);
}
zipd = (ZipDirectory*) zipf->central_directory;
for (i = 0; i < zipf->count; i++, zipd = ZIPDIR_NEXT (zipd))
{
printf ("%d: size:%d, name(#%d)%s, offset:%d\n",
i, zipd->size, zipd->filename_length,
ZIPDIR_FILENAME (zipd),
zipd->filestart);
}
}
#endif

58
gcc/java/zipfile.h Normal file
View file

@ -0,0 +1,58 @@
/* Definitions for using a zipped' archive.
Copyright (C) 1996 Free Software Foundation, Inc.
This program 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.
This program 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 GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, 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. */
struct ZipFile {
int fd;
long size;
long count;
long dir_size;
char *central_directory;
};
typedef struct ZipFile ZipFile;
struct ZipDirectory {
int direntry_size;
int filename_offset;
long size; /* length of file */
long filestart; /* start of file in archive */
long filename_length;
/* char mid_padding[...]; */
/* char filename[filename_length]; */
/* char end_padding[...]; */
};
typedef struct ZipDirectory ZipDirectory;
struct ZipFileCache {
struct ZipFile z;
struct ZipFileCache *next;
char *name;
};
extern struct ZipFileCache *SeenZipFiles;
#define ZIPDIR_FILENAME(ZIPD) ((char*)(ZIPD)+(ZIPD)->filename_offset)
#define ZIPDIR_NEXT(ZIPD) \
((ZipDirectory*)((char*)(ZIPD)+(ZIPD)->direntry_size))
#define ZIPMAGIC 0x504b0304