aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Tromey <tromey@redhat.com>2006-10-20 20:30:55 +0000
committerTom Tromey <tromey@redhat.com>2006-10-20 20:30:55 +0000
commitd96e812b338908008b7b1f96a3f11a266d7cede3 (patch)
tree31d10a013067266bf2845865e21d2e55dcaaf132
parente8a627f34f97e556fdfb7019eb9fe358314cacbc (diff)
* Make-lang.in (java): Removed gjnih, gcjh.
(JAVA_TARGET_INDEPENDENT_BIN_TOOLS): Likewise. (GCJH_OBJS): Removed. (GJNIH_OBJS): Likewise. (gjnih$(exeext)): Likewise. (gcjh$(exeext)): Likewise. (JAVA_MANFILES): Removed gcjh.1, gjnih.1. (java.install-common): Don't special case gcjh. (java.uninstall): Don't mention gcjh, gjnih. (java.mostlyclean): Likewise. (java.maintainer-clean): Likewise. (.INTERMEDIATE): Likewise. (gcjh.pod): Removed. (gjnih.pod): Likewise. (GCJH_TARGET_INSTALL_NAME): Removed. (java/gjavah-jni.o): Removed. (java/gjavah.o): Likewise. * config-lang.in (stagestuff): Removed gjnih, gcjh. * gjavah.c: Removed. git-svn-id: https://gcc.gnu.org/svn/gcc/branches/gcj-eclipse@117911 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/java/ChangeLog22
-rw-r--r--gcc/java/Make-lang.in66
-rw-r--r--gcc/java/config-lang.in2
-rw-r--r--gcc/java/gjavah.c2676
4 files changed, 33 insertions, 2733 deletions
diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog
index b5e140d65f2..b9a4b6bf480 100644
--- a/gcc/java/ChangeLog
+++ b/gcc/java/ChangeLog
@@ -1,3 +1,25 @@
+2006-10-20 Tom Tromey <tromey@redhat.com>
+
+ * Make-lang.in (java): Removed gjnih, gcjh.
+ (JAVA_TARGET_INDEPENDENT_BIN_TOOLS): Likewise.
+ (GCJH_OBJS): Removed.
+ (GJNIH_OBJS): Likewise.
+ (gjnih$(exeext)): Likewise.
+ (gcjh$(exeext)): Likewise.
+ (JAVA_MANFILES): Removed gcjh.1, gjnih.1.
+ (java.install-common): Don't special case gcjh.
+ (java.uninstall): Don't mention gcjh, gjnih.
+ (java.mostlyclean): Likewise.
+ (java.maintainer-clean): Likewise.
+ (.INTERMEDIATE): Likewise.
+ (gcjh.pod): Removed.
+ (gjnih.pod): Likewise.
+ (GCJH_TARGET_INSTALL_NAME): Removed.
+ (java/gjavah-jni.o): Removed.
+ (java/gjavah.o): Likewise.
+ * config-lang.in (stagestuff): Removed gjnih, gcjh.
+ * gjavah.c: Removed.
+
2006-10-17 Tom Tromey <tromey@redhat.com>
* jcf-dump.c (print_element_value): Expect a utf8 constant in the
diff --git a/gcc/java/Make-lang.in b/gcc/java/Make-lang.in
index 89ee570051f..8da6b9e6bd6 100644
--- a/gcc/java/Make-lang.in
+++ b/gcc/java/Make-lang.in
@@ -43,18 +43,16 @@
# Actual names to use when installing a native compiler.
JAVA_INSTALL_NAME := $(shell echo gcj|sed '$(program_transform_name)')
JAVA_TARGET_INSTALL_NAME := $(target_noncanonical)-$(shell echo gcj|sed '$(program_transform_name)')
-GCJH_TARGET_INSTALL_NAME := $(target_noncanonical)-$(shell echo gcjh|sed '$(program_transform_name)')
GCJ = gcj
# Define the names for selecting java in LANGUAGES.
java: jc1$(exeext) $(GCJ)$(exeext) jvgenmain$(exeext) \
- gcjh$(exeext) jv-scan$(exeext) jcf-dump$(exeext) \
- gjnih$(exeext)
+ jv-scan$(exeext) jcf-dump$(exeext)
# Define the name of target independent tools to be installed in $(bindir)
# Names are subject to changes
-JAVA_TARGET_INDEPENDENT_BIN_TOOLS = gcjh gjnih jv-scan jcf-dump
+JAVA_TARGET_INDEPENDENT_BIN_TOOLS = jv-scan jcf-dump
# Tell GNU make to ignore these if they exist.
.PHONY: java
@@ -107,14 +105,6 @@ JAVA_OBJS = java/parse.o java/class.o java/decl.o java/expr.o \
java/jcf-write.o java/buffer.o java/check-init.o java/jcf-depend.o \
java/jcf-path.o java/boehm.o java/java-gimplify.o
-GCJH_OBJS = java/gjavah.o java/jcf-io.o java/jcf-depend.o java/jcf-path.o \
- java/win32-host.o java/zextract.o version.o errors.o ggc-none.o \
- intl.o
-
-GJNIH_OBJS = java/gjavah-jni.o java/jcf-io.o java/jcf-depend.o java/jcf-path.o \
- java/win32-host.o java/zextract.o version.o errors.o \
- ggc-none.o intl.o
-
JVSCAN_OBJS = java/parse-scan.o java/jv-scan.o version.o intl.o
JCFDUMP_OBJS = java/jcf-dump.o java/jcf-io.o java/jcf-depend.o java/jcf-path.o \
@@ -137,14 +127,6 @@ jc1$(exeext): $(JAVA_OBJS) $(BACKEND) $(LIBDEPS)
$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ \
$(JAVA_OBJS) $(BACKEND) $(ZLIB) $(LIBICONV) $(LIBS)
-gcjh$(exeext): $(GCJH_OBJS) $(LIBDEPS)
- rm -f $@
- $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ $(GCJH_OBJS) $(CPPLIBS) $(ZLIB) $(LIBS)
-
-gjnih$(exeext): $(GJNIH_OBJS) $(LIBDEPS)
- rm -f $@
- $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ $(GJNIH_OBJS) $(CPPLIBS) $(ZLIB) $(LIBS)
-
jv-scan$(exeext): $(JVSCAN_OBJS) $(LIBDEPS)
rm -f $@
$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ $(JVSCAN_OBJS) $(LIBICONV) $(LIBS)
@@ -179,9 +161,9 @@ java.srcinfo: doc/gcj.info
java.dvi: doc/gcj.dvi
java.html: $(htmldir)/java/index.html
-JAVA_MANFILES = doc/gcj.1 doc/gcjh.1 doc/jv-scan.1 doc/jcf-dump.1 doc/gij.1 \
+JAVA_MANFILES = doc/gcj.1 doc/jv-scan.1 doc/jcf-dump.1 doc/gij.1 \
doc/jv-convert.1 doc/grmic.1 doc/grmiregistry.1 \
- doc/gcj-dbtool.1 doc/gjnih.1
+ doc/gcj-dbtool.1
java.man: $(JAVA_MANFILES)
@@ -191,14 +173,10 @@ java.srcman: $(JAVA_MANFILES)
check-java :
# Install hooks:
-# jc1, gcj, jvgenmain, and gcjh are installed elsewhere as part
+# jc1, gcj, and jvgenmain are installed elsewhere as part
# of $(COMPILERS).
# Install gcj as well as the target-independent tools.
-# For a native build, we special-case gcjh and also install
-# its explicitly-prefixed variant. This allows us to write
-# portable makefiles for both cross builds (where gcjh *must*
-# be explicitly prefixed) and native builds.
java.install-common: installdirs
-if [ -f $(GCJ)$(exeext) ]; then \
rm -f $(DESTDIR)$(bindir)/$(JAVA_INSTALL_NAME)$(exeext); \
@@ -218,13 +196,6 @@ java.install-common: installdirs
rm -f $(DESTDIR)$(bindir)/$$tool_transformed_name$(exeext); \
$(INSTALL_PROGRAM) $$tool$(exeext) $(DESTDIR)$(bindir)/$$tool_transformed_name$(exeext); \
chmod a+x $(DESTDIR)$(bindir)/$$tool_transformed_name$(exeext); \
- if [ -f $(GCJ)-cross$(exeext) ]; then \
- true; \
- elif [ $$tool = gcjh ]; then \
- rm -f $(DESTDIR)$(bindir)/$(GCJH_TARGET_INSTALL_NAME)$(exeext); \
- ( cd $(DESTDIR)$(bindir) && \
- $(LN) $$tool_transformed_name$(exeext) $(GCJH_TARGET_INSTALL_NAME)$(exeext) ); \
- fi; \
fi ; \
done
@@ -233,8 +204,6 @@ java.install-man:
java.uninstall:
-rm -rf $(DESTDIR)$(bindir)/$(JAVA_INSTALL_NAME)$(exeext)
-rm -rf $(DESTDIR)$(man1dir)/$(JAVA_INSTALL_NAME)$(man1ext)
- -rm -rf $(DESTDIR)$(man1dir)/gcjh$(man1ext)
- -rm -rf $(DESTDIR)$(man1dir)/gjnih$(man1ext)
-rm -rf $(DESTDIR)$(man1dir)/jv-scan$(man1ext)
-rm -rf $(DESTDIR)$(man1dir)/jcf-dump$(man1ext)
-rm -rf $(DESTDIR)$(man1dir)/gij$(man1ext)
@@ -252,14 +221,14 @@ java.mostlyclean:
-rm -f java/parse.c java/parse-scan.c
-rm -f java/*$(objext) $(DEMANGLER_PROG)
-rm -f java/*$(coverageexts)
- -rm -f jc1$(exeext) $(GCJ)$(exeext) jvgenmain$(exeext) gcjh$(exeext) \
- gjnih$(exeext) jv-scan$(exeext) jcf-dump$(exeext) s-java
+ -rm -f jc1$(exeext) $(GCJ)$(exeext) jvgenmain$(exeext) \
+ jv-scan$(exeext) jcf-dump$(exeext) s-java
java.clean:
java.distclean:
-rm -f java/config.status java/Makefile
-rm -f java/parse.output java/y.tab.c
java.maintainer-clean:
- -rm -f $(docobjdir)/gcj.1 $(docobjdir)/gcjh.1 $(docobjdir)/gjnih.1
+ -rm -f $(docobjdir)/gcj.1
-rm -f $(docobjdir)/jv-scan.1 $(docobjdir)/jcf-dump.1
-rm -f $(docobjdir)/gij.1
-rm -f $(docobjdir)/jv-convert.1
@@ -291,9 +260,6 @@ JAVA_LEX_C = java/lex.c java/keyword.h java/chartables.h
java/jcf-dump.o: $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(JAVA_TREE_H) \
java/jcf-dump.c java/jcf-reader.c java/jcf.h java/javaop.h java/javaop.def \
version.h $(GGC_H) intl.h
-java/gjavah.o: $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(JAVA_TREE_H) \
- java/gjavah.c java/jcf-reader.c java/jcf.h java/javaop.h version.h $(GGC_H) \
- intl.h
java/boehm.o: java/boehm.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TREE_H) $(JAVA_TREE_H) java/parse.h toplev.h
java/buffer.o: java/buffer.c $(CONFIG_H) java/buffer.h $(SYSTEM_H) coretypes.h \
@@ -373,14 +339,6 @@ java/jcf-path.o: java/jcf-path.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
-DDEFAULT_TARGET_VERSION=\"$(version)\" \
$(srcdir)/java/jcf-path.c $(OUTPUT_OPTION)
-# create gjnih's object
-java/gjavah-jni.o: $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(JAVA_TREE_H) \
- java/gjavah.c java/jcf-reader.c java/jcf.h java/javaop.h version.h $(GGC_H) \
- intl.h
- $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(ZLIBINC) \
- -DJNI_DEFAULT=1 \
- $(srcdir)/java/gjavah.c $(OUTPUT_OPTION)
-
TEXI_JAVA_FILES = java/gcj.texi $(gcc_docdir)/include/fdl.texi \
$(gcc_docdir)/include/gpl.texi $(gcc_docdir)/include/gcc-common.texi \
gcc-vers.texi
@@ -400,15 +358,11 @@ $(htmldir)/java/index.html: $(TEXI_JAVA_FILES)
rm -f $(@D)/*
$(TEXI2HTML) -I $(gcc_docdir)/include -I $(srcdir)/java -o $(@D) $<
-.INTERMEDIATE: gcj.pod gcjh.pod jv-scan.pod jcf-dump.pod gij.pod \
- jv-convert.pod grmic.pod grmiregistry.pod gcj-dbtool.pod gjnih.pod
+.INTERMEDIATE: gcj.pod jv-scan.pod jcf-dump.pod gij.pod \
+ jv-convert.pod grmic.pod grmiregistry.pod gcj-dbtool.pod
gcj.pod: java/gcj.texi
-$(TEXI2POD) -D gcj < $< > $@
-gcjh.pod: java/gcj.texi
- -$(TEXI2POD) -D gcjh < $< > $@
-gjnih.pod: java/gcj.texi
- -$(TEXI2POD) -D gjnih < $< > $@
jv-scan.pod: java/gcj.texi
-$(TEXI2POD) -D jv-scan < $< > $@
jcf-dump.pod: java/gcj.texi
diff --git a/gcc/java/config-lang.in b/gcc/java/config-lang.in
index d046c66fcaf..9219c12900f 100644
--- a/gcc/java/config-lang.in
+++ b/gcc/java/config-lang.in
@@ -34,7 +34,7 @@ language="java"
compilers="jc1\$(exeext) jvgenmain\$(exeext)"
-stagestuff="jc1\$(exeext) gcj\$(exeext) jvgenmain\$(exeext) gcjh\$(exeext) gjnih\$(exeext) jv-scan\$(exeext) jcf-dump\$(exeext)"
+stagestuff="jc1\$(exeext) gcj\$(exeext) jvgenmain\$(exeext) jv-scan\$(exeext) jcf-dump\$(exeext)"
gtfiles="\$(srcdir)/java/java-tree.h \$(srcdir)/java/jcf.h \$(srcdir)/java/lex.h \$(srcdir)/java/parse.h \$(srcdir)/java/builtins.c \$(srcdir)/java/class.c \$(srcdir)/java/constants.c \$(srcdir)/java/decl.c \$(srcdir)/java/expr.c \$(srcdir)/java/jcf-parse.c \$(srcdir)/java/jcf-write.c \$(srcdir)/java/lang.c \$(srcdir)/java/mangle.c \$(srcdir)/java/parse.y \$(srcdir)/java/resource.c"
diff --git a/gcc/java/gjavah.c b/gcc/java/gjavah.c
deleted file mode 100644
index 5907e95548a..00000000000
--- a/gcc/java/gjavah.c
+++ /dev/null
@@ -1,2676 +0,0 @@
-/* Program to write C++-suitable header files from a Java(TM) .class
- file. This is similar to SUN's javah.
-
-Copyright (C) 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
-Free Software Foundation, Inc.
-
-This file is part of GCC.
-
-GCC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GCC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.
-
-Java and all Java-based marks are trademarks or registered trademarks
-of Sun Microsystems, Inc. in the United States and other countries.
-The Free Software Foundation is independent of Sun Microsystems, Inc. */
-
-/* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tm.h"
-#include <math.h>
-
-#include "jcf.h"
-#include "tree.h"
-#include "version.h"
-#include "javaop.h"
-#include "java-tree.h"
-#include "java-opcodes.h"
-#include "ggc.h"
-#include "hashtab.h"
-#include "intl.h"
-
-#include <getopt.h>
-
-
-
-/* The output file. */
-FILE *out = NULL;
-
-/* Nonzero on failure. */
-static int found_error = 0;
-
-#ifdef JNI_DEFAULT
-#define TOOLNAME "gjnih"
-
-/* Nonzero if we're generating JNI output. */
-int flag_jni = 1;
-#else
-#define TOOLNAME "gcjh"
-
-int flag_jni = 0;
-#endif
-
-/* When nonzero, warn when source file is newer than matching class
- file. */
-int flag_newer = 1;
-
-/* Directory to place resulting files in. Set by -d option. */
-static const char *output_directory = "";
-
-/* Directory to place temporary file. Set by -td option. Currently unused. */
-static const 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;
-
-/* 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;
-
-/* Pass this macro the flags for a class and for a method. It will
- return true if the method should be considered `final'. */
-#define METHOD_IS_FINAL(Class, Method) \
- (((Class) & ACC_FINAL) || ((Method) & (ACC_FINAL | ACC_PRIVATE)))
-
-/* Pass this macro the flags for a method. It will return true if the
- method is native. */
-#define METHOD_IS_NATIVE(Method) \
- ((Method) & ACC_NATIVE)
-
-#define METHOD_IS_PRIVATE(Class, Method) \
- (((Method) & ACC_PRIVATE) != 0)
-
-/* We keep a linked list of all method names we have seen. This lets
- us determine if a method name and a field name are in conflict. */
-struct method_name
-{
- unsigned char *name;
- int length;
- unsigned char *signature;
- int sig_length;
- int is_native;
- struct method_name *next;
-};
-
-/* List of method names we've seen. */
-static struct method_name *method_name_list;
-
-static void print_field_info (FILE*, JCF*, int, int, JCF_u2);
-static void print_mangled_classname (FILE*, JCF*, const char*, int);
-static int print_cxx_classname (FILE*, const char*, JCF*, int, int);
-static void print_method_info (FILE*, JCF*, int, int, JCF_u2);
-static void print_c_decl (FILE*, JCF*, int, int, int, const char *, int);
-static void print_stub_or_jni (FILE*, JCF*, int, int, int, const char *, int);
-static void print_full_cxx_name (FILE*, JCF*, int, int, int, const char *, int);
-static void decompile_method (FILE*, JCF*, int) ATTRIBUTE_UNUSED;
-static void add_class_decl (FILE*, JCF*, JCF_u2);
-
-static void print_name (FILE *, JCF *, int);
-static void print_base_classname (FILE *, JCF *, int);
-static int utf8_cmp (const unsigned char *, int, const char *);
-static char *cxx_keyword_subst (const unsigned char *, int);
-static void generate_access (FILE *, JCF_u2);
-static int name_is_method_p (const unsigned char *, int);
-static char *get_field_name (JCF *, int, JCF_u2);
-static void print_field_name (FILE *, JCF *, int, JCF_u2);
-static const unsigned char *super_class_name (JCF *, int *);
-static void print_include (FILE *, const unsigned char *, int);
-static int gcjh_streq (const void *p1, const void *p2);
-static int throwable_p (const unsigned char *signature);
-static const unsigned char *
- decode_signature_piece (FILE *, const unsigned char *,
- const unsigned char *, int *);
-static void print_class_decls (FILE *, JCF *, int);
-static void error (const char *gmsgid, ...) ATTRIBUTE_PRINTF_1;
-static void usage (void) ATTRIBUTE_NORETURN;
-static void help (void) ATTRIBUTE_NORETURN;
-static void version (void) ATTRIBUTE_NORETURN;
-static int overloaded_jni_method_exists_p (const unsigned char *, int,
- const char *, int);
-static void jni_print_char (FILE *, int);
-static void jni_print_float (FILE *, jfloat);
-static void jni_print_double (FILE *, jdouble);
-static void decompile_return_statement (FILE *, JCF *, int, int, int);
-
-static void handle_inner_classes (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)
-
-/* We pass over fields twice. The first time we just note the types
- of the fields and then the start of the methods. Then we go back
- and parse the fields for real. This is ugly. */
-static int field_pass;
-/* Likewise we pass over methods twice. The first time we generate
- class decl information; the second time we generate actual method
- decls. */
-static int method_pass;
-
-#define HANDLE_END_FIELD() \
- if (field_pass) \
- { \
- if (out && ! stubs) \
- print_field_info (out, jcf, current_field_name, \
- current_field_signature, \
- current_field_flags); \
- } \
- else if (! stubs && ! flag_jni) \
- add_class_decl (out, jcf, current_field_signature);
-
-#define HANDLE_CONSTANTVALUE(VALUEINDEX) current_field_value = (VALUEINDEX)
-
-static int method_declared = 0;
-static int method_access = 0;
-static int method_printed = 0;
-static int method_synthetic = 0;
-static int method_signature = 0;
-
-/* Set to 1 while the very first data member of a class is being handled. */
-static int is_first_data_member = 0;
-
-#define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
- { \
- method_synthetic = 0; \
- method_printed = 0; \
- decompiled = 0; \
- method_signature = SIGNATURE; \
- if (ATTRIBUTE_COUNT) \
- method_synthetic = peek_attribute (jcf, ATTRIBUTE_COUNT, \
- (const char *)"Synthetic", 9); \
- /* If a synthetic methods have been declared, its attribute aren't \
- worth reading (and triggering side-effects). We skip them an \
- set ATTRIBUTE_COUNT to zero so that they'll be skipped in \
- jcf_parse_one_method. */ \
- if (method_synthetic) \
- { \
- skip_attribute (jcf, ATTRIBUTE_COUNT); \
- ATTRIBUTE_COUNT = 0; \
- } \
- if (method_pass && !method_synthetic) \
- { \
- if (out) \
- print_method_info (out, jcf, NAME, SIGNATURE, \
- ACCESS_FLAGS); \
- } \
- else if (!method_synthetic) \
- { \
- print_method_info (NULL, jcf, NAME, SIGNATURE, \
- ACCESS_FLAGS); \
- if (! stubs && ! flag_jni) \
- add_class_decl (out, jcf, SIGNATURE); \
- } \
- }
-
-/* Only include byte-code decompilation optimizations for ELF targets
- since the generated headers are only known to work with ELF weak
- symbol semantics. Specifically, these optimizations are known to
- not work on PE-COFF and possibly others. */
-#ifdef OBJECT_FORMAT_ELF
-#define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
- if (out && method_declared) decompile_method (out, jcf, CODE_LENGTH);
-#endif
-
-static int decompiled = 0;
-#define HANDLE_END_METHOD() \
- if (out && method_printed && !method_synthetic) \
- fputs (decompiled || stubs ? "\n" : ";\n", out);
-
-#define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT) handle_inner_classes (COUNT)
-
-/* We're going to need {peek,skip}_attribute, enable their definition. */
-#define NEED_PEEK_ATTRIBUTE
-#define NEED_SKIP_ATTRIBUTE
-
-#include "jcf-reader.c"
-
-/* Print an error message and set found_error.
- Not really gcc-internal-format message, but as error elsewhere
- uses it, assume all users will use intersection between
- c-format and gcc-internal-format. */
-static void
-error (const char *gmsgid, ...)
-{
- va_list ap;
-
- va_start (ap, gmsgid);
-
- fprintf (stderr, TOOLNAME ": ");
- vfprintf (stderr, _(gmsgid), ap);
- va_end (ap);
- fprintf (stderr, "\n");
- found_error = 1;
-}
-
-/* Print a single-precision float, suitable for parsing by g++. */
-static void
-jni_print_float (FILE *stream, jfloat f)
-{
- /* It'd be nice to use __builtin_nan/__builtin_inf here but they don't
- work in data initializers. FIXME. */
- if (JFLOAT_FINITE (f))
- {
- if (flag_jni)
- {
- fputs (" ", out);
- if (f.negative)
- putc ('-', stream);
- if (f.exponent)
- fprintf (stream, "0x1.%.6xp%+df",
- ((unsigned int)f.mantissa) << 1,
- f.exponent - JFLOAT_EXP_BIAS);
- else
- /* Exponent of 0x01 is -125; exponent of 0x00 is *also* -125,
- because the implicit leading 1 bit is no longer present. */
- fprintf (stream, "0x0.%.6xp%+df",
- ((unsigned int)f.mantissa) << 1,
- f.exponent + 1 - JFLOAT_EXP_BIAS);
- }
- }
- if (! flag_jni)
- fputs (";\n", stream);
-}
-
-/* Print a double-precision float, suitable for parsing by g++. */
-static void
-jni_print_double (FILE *stream, jdouble f)
-{
- /* It'd be nice to use __builtin_nan/__builtin_inf here but they don't
- work in data initializers. FIXME. */
- if (JDOUBLE_FINITE (f))
- {
- if (flag_jni)
- {
- fputs (" ", out);
- if (f.negative)
- putc ('-', stream);
- if (f.exponent)
- fprintf (stream, "0x1.%.5x%.8xp%+d",
- f.mantissa0, f.mantissa1,
- f.exponent - JDOUBLE_EXP_BIAS);
- else
- /* Exponent of 0x001 is -1022; exponent of 0x000 is *also* -1022,
- because the implicit leading 1 bit is no longer present. */
- fprintf (stream, "0x0.%.5x%.8xp%+d",
- f.mantissa0, f.mantissa1,
- f.exponent + 1 - JDOUBLE_EXP_BIAS);
- }
- }
- fputs (flag_jni ? "\n" : ";\n", stream);
-}
-
-/* Print a character, appropriately mangled for JNI. */
-
-static void
-jni_print_char (FILE *stream, int ch)
-{
- if (! flag_jni)
- jcf_print_char (stream, ch);
- else if (ch == '(' || ch == ')')
- {
- /* Ignore. */
- }
- else if (ch == '_')
- fputs ("_1", stream);
- else if (ch == ';')
- fputs ("_2", stream);
- else if (ch == '[')
- fputs ("_3", stream);
- else if (ch == '/')
- fputs ("_", stream);
- else if (ISALNUM (ch))
- fputc (ch, stream);
- else
- {
- /* "Unicode" character. */
- fprintf (stream, "_0%04x", ch);
- }
-}
-
-/* Print a name from the class data. If the index does not point to a
- string, an error results. */
-
-static void
-print_name (FILE* stream, JCF* jcf, int name_index)
-{
- if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
- {
- fprintf (stream, "<not a UTF8 constant>");
- found_error = 1;
- }
- else if (! flag_jni)
- jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf, name_index),
- JPOOL_UTF_LENGTH (jcf, name_index));
- else
- {
- /* For JNI we must correctly quote each character. */
- const unsigned char *str = JPOOL_UTF_DATA (jcf, name_index);
- int length = JPOOL_UTF_LENGTH (jcf, name_index);
- const unsigned char *limit = str + length;
- while (str < limit)
- {
- int ch = UTF8_GET (str, limit);
- if (ch < 0)
- {
- fprintf (stream, "\\<invalid>");
- return;
- }
- jni_print_char (stream, ch);
- }
- }
-}
-
-/* Print base name of class. The base name is everything after the
- final separator. */
-
-static void
-print_base_classname (FILE *stream, JCF *jcf, int index)
-{
- int name_index = JPOOL_USHORT1 (jcf, index);
- int len;
- const 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, -1 if STR is "less" than NAME,
- and 1 if STR is "greater" than NAME. */
-
-static int
-utf8_cmp (const unsigned char *str, int length, const char *name)
-{
- const unsigned char *limit = str + length;
- int i;
-
- for (i = 0; name[i]; ++i)
- {
- int ch = UTF8_GET (str, limit);
- if (ch != name[i])
- return ch - name[i];
- }
-
- return str == limit ? 0 : 1;
-}
-
-/* This is a sorted list of all C++ keywords. */
-
-static const char *const cxx_keywords[] =
-{
- "_Complex",
- "__alignof",
- "__alignof__",
- "__asm",
- "__asm__",
- "__attribute",
- "__attribute__",
- "__builtin_va_arg",
- "__complex",
- "__complex__",
- "__const",
- "__const__",
- "__extension__",
- "__imag",
- "__imag__",
- "__inline",
- "__inline__",
- "__label__",
- "__null",
- "__real",
- "__real__",
- "__restrict",
- "__restrict__",
- "__signed",
- "__signed__",
- "__typeof",
- "__typeof__",
- "__volatile",
- "__volatile__",
- "and",
- "and_eq",
- "asm",
- "auto",
- "bitand",
- "bitor",
- "bool",
- "break",
- "case",
- "catch",
- "char",
- "class",
- "compl",
- "const",
- "const_cast",
- "continue",
- "default",
- "delete",
- "do",
- "double",
- "dynamic_cast",
- "else",
- "enum",
- "explicit",
- "export",
- "extern",
- "false",
- "float",
- "for",
- "friend",
- "goto",
- "if",
- "inline",
- "int",
- "long",
- "mutable",
- "namespace",
- "new",
- "not",
- "not_eq",
- "operator",
- "or",
- "or_eq",
- "private",
- "protected",
- "public",
- "register",
- "reinterpret_cast",
- "return",
- "short",
- "signed",
- "sizeof",
- "static",
- "static_cast",
- "struct",
- "switch",
- "template",
- "this",
- "throw",
- "true",
- "try",
- "typedef",
- "typeid",
- "typename",
- "typeof",
- "union",
- "unsigned",
- "using",
- "virtual",
- "void",
- "volatile",
- "wchar_t",
- "while",
- "xor",
- "xor_eq"
-};
-
-
-/* If NAME is the name of a C++ keyword, then return an override name.
- This is a name that can be used in place of the keyword.
- Otherwise, return NULL. The return value is malloc()d. */
-
-static char *
-cxx_keyword_subst (const unsigned char *str, int length)
-{
- int last = ARRAY_SIZE (cxx_keywords);
- int first = 0;
- int mid = (last + first) / 2;
- int old = -1;
-
- for (mid = (last + first) / 2;
- mid != old;
- old = mid, mid = (last + first) / 2)
- {
- int kwl = strlen (cxx_keywords[mid]);
- int min_length = kwl > length ? length : kwl;
- int r = utf8_cmp (str, min_length, cxx_keywords[mid]);
-
- if (r == 0)
- {
- int i;
-
- /* Skip all trailing `$'. */
- for (i = min_length; i < length && str[i] == '$'; ++i)
- ;
- /* We've only found a match if all the remaining characters
- are `$'. */
- if (i == length)
- {
- char *dup = XNEWVEC (char, 2 + length - min_length + kwl);
- strcpy (dup, cxx_keywords[mid]);
- for (i = kwl; i < length + 1; ++i)
- dup[i] = '$';
- dup[i] = '\0';
- return dup;
- }
- r = 1;
- }
-
- if (r < 0)
- last = mid;
- else
- first = mid;
- }
- return NULL;
-}
-
-/* Generate an access control keyword based on FLAGS. */
-
-static void
-generate_access (FILE *stream, JCF_u2 flags)
-{
- if ((flags & ACC_VISIBILITY) == last_access)
- return;
- last_access = (flags & ACC_VISIBILITY);
-
- switch (last_access)
- {
- case 0:
- fputs ("public: // actually package-private\n", stream);
- break;
- case ACC_PUBLIC:
- fputs ("public:\n", stream);
- break;
- case ACC_PRIVATE:
- fputs ("private:\n", stream);
- break;
- case ACC_PROTECTED:
- fputs ("public: // actually protected\n", stream);
- break;
- default:
- found_error = 1;
- fprintf (stream, "#error unrecognized visibility %d\n",
- (flags & ACC_VISIBILITY));
- break;
- }
-}
-
-/* See if NAME is already the name of a method. */
-static int
-name_is_method_p (const unsigned char *name, int length)
-{
- struct method_name *p;
-
- for (p = method_name_list; p != NULL; p = p->next)
- {
- if (p->length == length && ! memcmp (p->name, name, length))
- return 1;
- }
- return 0;
-}
-
-/* Free the method name list. */
-static void
-free_method_name_list (void)
-{
- struct method_name *p = method_name_list;
- while (p != NULL)
- {
- struct method_name *next = p->next;
- free (p->name);
- free (p->signature);
- free (p);
- p = next;
- }
- method_name_list = NULL;
-}
-
-/* If there is already a native method named NAME, whose signature is not
- SIGNATURE, then return true. Otherwise return false. */
-static int
-overloaded_jni_method_exists_p (const unsigned char *name, int length,
- const char *signature, int sig_length)
-{
- struct method_name *p;
-
- for (p = method_name_list; p != NULL; p = p->next)
- {
- if (p->is_native
- && p->length == length
- && ! memcmp (p->name, name, length)
- && (p->sig_length != sig_length
- || memcmp (p->signature, signature, sig_length)))
- return 1;
- }
- return 0;
-}
-
-/* Get name of a field. This handles renamings due to C++ clash. */
-static char *
-get_field_name (JCF *jcf, int name_index, JCF_u2 flags)
-{
- unsigned char *name = JPOOL_UTF_DATA (jcf, name_index);
- int length = JPOOL_UTF_LENGTH (jcf, name_index);
- char *override;
-
- if (name_is_method_p (name, length))
- {
- /* This field name matches a method. So override the name with
- a dummy name. This is yucky, but it isn't clear what else to
- do. FIXME: if the field is static, then we'll be in real
- trouble. */
- if ((flags & ACC_STATIC))
- {
- error ("static field has same name as method");
- return NULL;
- }
-
- override = XNEWVEC (char, length + 3);
- memcpy (override, name, length);
- strcpy (override + length, "__");
- }
- else if (flag_jni)
- override = NULL;
- else
- override = cxx_keyword_subst (name, length);
-
- return override;
-}
-
-/* Print a field name. Convenience function for use with
- get_field_name. */
-static void
-print_field_name (FILE *stream, JCF *jcf, int name_index, JCF_u2 flags)
-{
- char *override = get_field_name (jcf, name_index, flags);
-
- if (override)
- {
- fputs (override, stream);
- free (override);
- }
- else
- jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf, name_index),
- JPOOL_UTF_LENGTH (jcf, name_index));
-}
-
-static void
-print_field_info (FILE *stream, JCF* jcf, int name_index, int sig_index,
- JCF_u2 flags)
-{
- char *override = NULL;
-
- if (! flag_jni)
- generate_access (stream, flags);
- if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
- {
- fprintf (stream, "<not a UTF8 constant>");
- found_error = 1;
- return;
- }
-
- if (flag_jni)
- {
- /* For JNI we only want to print real constants. */
- int val;
- if (! (flags & ACC_STATIC)
- || ! (flags & ACC_FINAL)
- || current_field_value <= 0)
- return;
- val = JPOOL_TAG (jcf, current_field_value);
- if (val != CONSTANT_Integer && val != CONSTANT_Long
- && val != CONSTANT_Float && val != CONSTANT_Double)
- return;
- }
- else
- {
- /* Initial indentation. */
- fputs (" ", stream);
- }
-
- if ((flags & ACC_STATIC))
- {
- if (flag_jni)
- {
- print_cxx_classname (stream, "#undef ", jcf, jcf->this_class, 1);
- fputs ("_", stream);
- print_field_name (stream, jcf, name_index, 0);
- fputs ("\n", stream);
- print_cxx_classname (stream, "#define ", jcf, jcf->this_class, 1);
- fputs ("_", stream);
- }
- else
- fputs ("static ", stream);
-
- if ((flags & ACC_FINAL) && current_field_value > 0)
- {
- char buffer[25];
- int done = 1;
-
- switch (JPOOL_TAG (jcf, current_field_value))
- {
- case CONSTANT_Integer:
- {
- jint num;
- int most_negative = 0;
- if (! flag_jni)
- fputs ("const jint ", stream);
- print_field_name (stream, jcf, name_index, 0);
- fputs (flag_jni ? " " : " = ", stream);
- num = JPOOL_INT (jcf, current_field_value);
- /* We single out the most negative number to print
- specially. This avoids later warnings from g++. */
- if (num == (jint) 0x80000000)
- {
- most_negative = 1;
- ++num;
- }
- format_int (buffer, (jlong) num, 10);
- fprintf (stream, "%sL%s%s\n", buffer,
- most_negative ? " - 1" : "",
- flag_jni ? "" : ";");
- }
- break;
- case CONSTANT_Long:
- {
- jlong num;
- int most_negative = 0;
- if (! flag_jni)
- fputs ("const jlong ", stream);
- print_field_name (stream, jcf, name_index, 0);
- fputs (flag_jni ? " " : " = ", stream);
- num = JPOOL_LONG (jcf, current_field_value);
- /* We single out the most negative number to print
- specially.. This avoids later warnings from g++. */
- if (num == (jlong) 0x8000000000000000LL)
- {
- most_negative = 1;
- ++num;
- }
- format_int (buffer, num, 10);
- fprintf (stream, "%sLL%s%s\n", buffer,
- most_negative ? " - 1" :"",
- flag_jni ? "" : ";");
- }
- break;
- case CONSTANT_Float:
- {
- jfloat fnum = JPOOL_FLOAT (jcf, current_field_value);
- if (! flag_jni)
- fputs ("const jfloat ", stream);
- print_field_name (stream, jcf, name_index, 0);
- jni_print_float (stream, fnum);
- }
- break;
- case CONSTANT_Double:
- {
- jdouble dnum = JPOOL_DOUBLE (jcf, current_field_value);
- if (! flag_jni)
- fputs ("const jdouble ", stream);
- print_field_name (stream, jcf, name_index, 0);
- jni_print_double (stream, dnum);
- }
- break;
- default:
- /* We can't print this as a constant, but we can still
- print something sensible. */
- done = 0;
- break;
- }
-
- if (done)
- return;
- }
- }
-
- /* assert (! flag_jni); */
- override = get_field_name (jcf, name_index, flags);
- print_c_decl (stream, jcf, name_index, sig_index, 0, override, flags);
- fputs (";\n", stream);
-
- if (override)
- free (override);
-}
-
-
-static void
-print_method_info (FILE *stream, JCF* jcf, int name_index, int sig_index,
- JCF_u2 flags)
-{
- const unsigned char *str;
- int length, is_init = 0;
- char *override = NULL;
-
- method_declared = 0;
- method_access = flags;
- if (stream && 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 the internally generated method <clinit>. However,
- treat <init> as a constructor. */
- if (! utf8_cmp (str, length, "<init>"))
- is_init = 1;
- else if (! METHOD_IS_FINAL (jcf->access_flags, flags)
- && ! (flags & ACC_STATIC))
- {
- /* FIXME: i18n bug here. Order of prints should not be
- fixed. */
- fprintf (stderr, _("ignored method '"));
- jcf_print_utf8 (stderr, str, length);
- fprintf (stderr, _("' marked virtual\n"));
- found_error = 1;
- return;
- }
- else
- return;
- }
-
- /* During the first method pass, build a list of method names. This will
- be used to determine if field names conflict with method names. */
- if (! stream)
- {
- struct method_name *nn;
-
- nn = XNEW (struct method_name);
- nn->name = XNEWVEC (unsigned char, length);
- memcpy (nn->name, str, length);
- nn->length = length;
- nn->next = method_name_list;
- nn->sig_length = JPOOL_UTF_LENGTH (jcf, sig_index);
- nn->signature = XNEWVEC (unsigned char, nn->sig_length);
- nn->is_native = METHOD_IS_NATIVE (flags);
- memcpy (nn->signature, JPOOL_UTF_DATA (jcf, sig_index),
- nn->sig_length);
- method_name_list = nn;
-
- /* The rest of this function doesn't matter. */
- return;
- }
-
- /* We don't worry about overrides in JNI mode. */
- if (! flag_jni)
- {
- /* We can't generate a method whose name is a C++ reserved word.
- We can't just ignore the function, because that will cause
- incorrect code to be generated if the function is virtual
- (not only for calls to this function for for other functions
- after it in the vtbl). So we give it a dummy name instead. */
- override = cxx_keyword_subst (str, length);
- }
-
- if (! stubs && ! flag_jni)
- {
- method_printed = 1;
-
- generate_access (stream, flags);
-
- fputs (" ", out);
- if ((flags & ACC_STATIC))
- fputs ("static ", out);
- else if (! METHOD_IS_PRIVATE (jcf->access_flags, flags))
- {
- /* Don't print `virtual' if we have a constructor. */
- if (! is_init)
- fputs ("virtual ", out);
- }
- print_c_decl (out, jcf, name_index, sig_index, is_init, override, flags);
-
- if ((flags & ACC_ABSTRACT))
- fputs (" = 0", out);
- else
- method_declared = 1;
- }
- else
- {
- if (METHOD_IS_NATIVE (flags))
- {
- method_printed = 1;
- print_stub_or_jni (out, jcf, name_index, sig_index,
- is_init, override, flags);
- }
- }
-
- if (override)
- free (override);
-}
-
-/* A helper for the decompiler which prints a `return' statement where
- the type is a reference type. If METHODTYPE and OBJECTTYPE are not
- identical, we emit a cast. We do this because the C++ compiler
- doesn't know that a reference can be cast to the type of an
- interface it implements. METHODTYPE is the index of the method's
- signature. NAMEINDEX is the index of the field name; -1 for
- `this'. OBJECTTYPE is the index of the object's type. */
-static void
-decompile_return_statement (FILE *out, JCF *jcf, int methodtype,
- int nameindex, int objecttype)
-{
- int cast = 0;
- int obj_name_len, method_name_len;
- const unsigned char *obj_data, *method_data;
-
- obj_name_len = JPOOL_UTF_LENGTH (jcf, objecttype);
- obj_data = JPOOL_UTF_DATA (jcf, objecttype);
-
- method_name_len = JPOOL_UTF_LENGTH (jcf, methodtype);
- method_data = JPOOL_UTF_DATA (jcf, methodtype);
-
- /* Skip forward to return type part of method. */
- while (*method_data != ')')
- {
- ++method_data;
- --method_name_len;
- }
- /* Skip past `)'. */
- ++method_data;
- --method_name_len;
-
- /* If we see an `L', skip it and the trailing `;'. */
- if (method_data[0] == 'L' && method_data[method_name_len - 1] == ';')
- {
- ++method_data;
- method_name_len -= 2;
- }
- if (obj_data[0] == 'L' && obj_data[obj_name_len - 1] == ';')
- {
- ++obj_data;
- obj_name_len -= 2;
- }
-
- /* FIXME: if METHODTYPE is a superclass of OBJECTTYPE then we don't
- need a cast. Right now there is no way to determine if this is
- the case. */
- if (method_name_len != obj_name_len)
- cast = 1;
- else
- {
- int i;
- for (i = 0; i < method_name_len; ++i)
- {
- if (method_data[i] != obj_data[i])
- {
- cast = 1;
- break;
- }
- }
- }
-
- fputs (" { return ", out);
-
- if (cast)
- {
- int array_depth = 0;
- const unsigned char *limit;
-
- fputs ("reinterpret_cast<", out);
-
- while (*method_data == '[')
- {
- ++method_data;
- ++array_depth;
- --method_name_len;
- fputs ("JArray<", out);
- }
-
- /* Leading space to avoid C++ digraphs. */
- fputs (" ::", out);
-
- /* If we see an `L', skip it and the trailing `;'. Only do this
- if we've seen an array specification. If we don't have an
- array then the `L' was stripped earlier. */
- if (array_depth && method_data[0] == 'L'
- && method_data[method_name_len - 1] == ';')
- {
- ++method_data;
- method_name_len -= 2;
- }
-
- limit = method_data + method_name_len;
- while (method_data < limit)
- {
- int ch = UTF8_GET (method_data, limit);
- if (ch == '/')
- fputs ("::", out);
- else
- jcf_print_char (out, ch);
- }
- fputs (" *", out);
-
- /* Close each array. */
- while (array_depth > 0)
- {
- fputs ("> *", out);
- --array_depth;
- }
-
- /* Close the cast. */
- fputs ("> (", out);
- }
-
- if (nameindex == -1)
- fputs ("this", out);
- else
- print_field_name (out, jcf, nameindex, 0);
-
- if (cast)
- fputs (")", out);
-
- fputs ("; }", out);
-}
-
-
-/* Try to decompile a method body. Right now we just try to handle a
- simple case that we can do. Expand as desired. */
-static void
-decompile_method (FILE *out, JCF *jcf, int code_len)
-{
- const unsigned char *codes = jcf->read_ptr;
- int index;
- uint16 name_and_type, name;
-
- /* If the method is synchronized, don't touch it. */
- if ((method_access & ACC_SYNCHRONIZED))
- return;
-
- /* The first case is 'return field'; but we only want to do this for
- non-static methods. */
- if (! (method_access & ACC_STATIC)
- && code_len == 5
- && codes[0] == OPCODE_aload_0
- && codes[1] == OPCODE_getfield
- && (codes[4] == OPCODE_areturn
- || codes[4] == OPCODE_dreturn
- || codes[4] == OPCODE_freturn
- || codes[4] == OPCODE_ireturn
- || codes[4] == OPCODE_lreturn))
- {
- /* Found code like `return FIELD'. */
- index = (codes[2] << 8) | codes[3];
- /* FIXME: ensure that tag is CONSTANT_Fieldref. */
- name_and_type = JPOOL_USHORT2 (jcf, index);
- /* FIXME: ensure that tag is CONSTANT_NameAndType. */
- name = JPOOL_USHORT1 (jcf, name_and_type);
- if (codes[4] == OPCODE_areturn)
- decompile_return_statement (out, jcf, method_signature,
- name, JPOOL_USHORT2 (jcf, name_and_type));
- else
- {
- fputs (" { return ", out);
- /* FIXME: flags. */
- print_field_name (out, jcf, name, 0);
- fputs ("; }", out);
- }
- decompiled = 1;
- }
- else if (code_len == 2
- && codes[0] == OPCODE_aload_0
- && codes[1] == OPCODE_areturn
- /* We're going to generate `return this'. This only makes
- sense for non-static methods. */
- && ! (method_access & ACC_STATIC))
- {
- decompile_return_statement (out, jcf, method_signature, -1,
- JPOOL_USHORT1 (jcf, jcf->this_class));
- decompiled = 1;
- }
- else if (code_len == 1 && codes[0] == OPCODE_return)
- {
- /* Found plain `return'. */
- fputs (" { }", out);
- decompiled = 1;
- }
- else if (code_len == 2
- && codes[0] == OPCODE_aconst_null
- && codes[1] == OPCODE_areturn)
- {
- /* Found `return null'. We don't want to depend on NULL being
- defined. */
- fputs (" { return 0; }", out);
- decompiled = 1;
- }
-}
-
-/* Like strcmp, but invert the return result for the hash table. This
- should probably be in hashtab.c to complement the existing string
- hash function. */
-static int
-gcjh_streq (const void *p1, const void *p2)
-{
- return ! strcmp ((char *) p1, (char *) p2);
-}
-
-/* Return 1 if the initial part of CLNAME names a subclass of throwable,
- or 0 if not. CLNAME may be extracted from a signature, and can be
- terminated with either `;' or NULL. */
-static int
-throwable_p (const unsigned char *clname)
-{
- int length;
- unsigned char *current;
- int i;
- int result = 0;
-
- /* We keep two hash tables of class names. In one we list all the
- classes which are subclasses of Throwable. In the other we will
- all other classes. We keep two tables to make the code a bit
- simpler; we don't have to have a structure mapping class name to
- a `throwable?' bit. */
- static htab_t throw_hash;
- static htab_t non_throw_hash;
- static int init_done = 0;
-
- if (! init_done)
- {
- void **slot;
- unsigned char *str;
-
- /* Self-initializing. The cost of this really doesn't matter.
- We also don't care about freeing these, either. */
- throw_hash = htab_create (10, htab_hash_string, gcjh_streq,
- (htab_del) free);
- non_throw_hash = htab_create (10, htab_hash_string, gcjh_streq,
- (htab_del) free);
-
- /* Make sure the root classes show up in the tables. */
- str = (unsigned char *) xstrdup ("java.lang.Throwable");
- slot = htab_find_slot (throw_hash, str, INSERT);
- *slot = str;
-
- str = (unsigned char *) xstrdup ("java.lang.Object");
- slot = htab_find_slot (non_throw_hash, str, INSERT);
- *slot = str;
-
- init_done = 1;
- }
-
- for (length = 0; clname[length] != ';' && clname[length] != '\0'; ++length)
- ;
- current = XNEWVEC (unsigned char, length + 1);
- for (i = 0; i < length; ++i)
- current[i] = clname[i] == '/' ? '.' : clname[i];
- current[length] = '\0';
-
- /* We don't compute the hash slot here because the table might be
- modified by the recursion. In that case the slot could be
- invalidated. */
- if (htab_find (throw_hash, current))
- result = 1;
- else if (htab_find (non_throw_hash, current))
- result = 0;
- else
- {
- JCF jcf;
- void **slot;
- unsigned char *super, *tmp;
- int super_length = -1;
- const char *classfile_name = find_class ((char *) current, strlen ((const char *) current),
- &jcf, 0);
-
- if (! classfile_name)
- {
- error ("couldn't find class %s", current);
- return 0;
- }
- if (jcf_parse_preamble (&jcf) != 0
- || jcf_parse_constant_pool (&jcf) != 0
- || verify_constant_pool (&jcf) > 0)
- {
- error ("parse error while reading %s", classfile_name);
- return 0;
- }
- jcf_parse_class (&jcf);
-
- tmp = (unsigned char *) super_class_name (&jcf, &super_length);
- super = XNEWVEC (unsigned char, super_length + 1);
- memcpy (super, tmp, super_length);
- super[super_length] = '\0';
-
- result = throwable_p (super);
- slot = htab_find_slot (result ? throw_hash : non_throw_hash,
- current, INSERT);
- *slot = current;
- current = NULL;
-
- JCF_FINISH (&jcf);
- }
-
- return result;
-}
-
-/* Print one piece of a signature. Returns pointer to next parseable
- character on success, NULL on error. */
-static const unsigned char *
-decode_signature_piece (FILE *stream, const unsigned char *signature,
- const unsigned char *limit, int *need_space)
-{
- const char *ctype;
- int array_depth = 0;
-
- switch (signature[0])
- {
- case '[':
- /* More spaghetti. */
-
- array_loop:
- for (signature++; (signature < limit
- && ISDIGIT (*signature)); signature++)
- ;
- switch (*signature)
- {
- case 'B':
- ctype = "jbyteArray";
- break;
- case 'C':
- ctype = "jcharArray";
- break;
- case 'D':
- ctype = "jdoubleArray";
- break;
- case 'F':
- ctype = "jfloatArray";
- break;
- case 'I':
- ctype = "jintArray";
- break;
- case 'S':
- ctype = "jshortArray";
- break;
- case 'J':
- ctype = "jlongArray";
- break;
- case 'Z':
- ctype = "jbooleanArray";
- break;
- case '[':
- /* We have a nested array. */
- ++array_depth;
- if (! flag_jni)
- fputs ("JArray<", stream);
- goto array_loop;
-
- case 'L':
- /* We have to generate a reference to JArray here, so that
- our output matches what the compiler does. */
- ++signature;
- /* Space between `<' and `:' to avoid C++ digraphs. */
- if (! flag_jni)
- fputs ("JArray< ::", stream);
- while (signature < limit && *signature != ';')
- {
- int ch = UTF8_GET (signature, limit);
- if (! flag_jni)
- {
- if (ch == '/')
- fputs ("::", stream);
- else
- jcf_print_char (stream, ch);
- }
- }
- if (! flag_jni)
- fputs (" *> *", stream);
- *need_space = 0;
- ctype = NULL;
- break;
- default:
- /* Unparseable signature. */
- return NULL;
- }
-
- /* If the previous iterations left us with something to print,
- print it. For JNI, we always print `jobjectArray' in the
- nested cases. */
- if (flag_jni && (ctype == NULL || array_depth > 0))
- {
- ctype = "jobjectArray";
- *need_space = 1;
- }
- /* The `printit' case will advance SIGNATURE for us. If we
- don't go there, we must advance past the `;' ourselves. */
- if (ctype != NULL)
- goto printit;
- ++signature;
- break;
-
- case '(':
- case ')':
- /* This shouldn't happen. */
- return NULL;
-
- case 'B': ctype = "jbyte"; goto printit;
- case 'C': ctype = "jchar"; goto printit;
- case 'D': ctype = "jdouble"; goto printit;
- case 'F': ctype = "jfloat"; goto printit;
- case 'I': ctype = "jint"; goto printit;
- case 'J': ctype = "jlong"; goto printit;
- case 'S': ctype = "jshort"; goto printit;
- case 'Z': ctype = "jboolean"; goto printit;
- case 'V': ctype = "void"; goto printit;
- case 'L':
- if (flag_jni)
- {
- /* We know about certain types and special-case their names. */
- if (! strncmp ((const char *) signature, "Ljava/lang/String;",
- sizeof ("Ljava/lang/String;") -1))
- ctype = "jstring";
- else if (! strncmp ((const char *) signature, "Ljava/lang/Class;",
- sizeof ("Ljava/lang/Class;") - 1))
- ctype = "jclass";
- /* Skip leading 'L' for throwable_p call. */
- else if (throwable_p (signature + 1))
- ctype = "jthrowable";
- else
- ctype = "jobject";
-
- while (*signature && *signature != ';')
- ++signature;
-
- goto printit;
- }
- /* Print a leading "::" so we look in the right namespace. */
- fputs ("::", stream);
- ++signature;
- while (*signature && *signature != ';')
- {
- int ch = UTF8_GET (signature, limit);
- if (ch == '/')
- fputs ("::", stream);
- else
- jcf_print_char (stream, ch);
- }
- fputs (" *", stream);
- if (*signature == ';')
- signature++;
- *need_space = 0;
- break;
- default:
- *need_space = 1;
- jni_print_char (stream, *signature++);
- break;
- printit:
- signature++;
- *need_space = 1;
- fputs (ctype, stream);
- break;
- }
-
- if (! flag_jni)
- {
- while (array_depth-- > 0)
- fputs ("> *", stream);
- }
-
- return signature;
-}
-
-static void
-print_c_decl (FILE* stream, JCF* jcf, int name_index, int signature_index,
- int is_init, const char *name_override, int flags)
-{
- if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
- {
- fprintf (stream, "<not a UTF8 constant>");
- found_error = 1;
- }
- else
- {
- int length = JPOOL_UTF_LENGTH (jcf, signature_index);
- const unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
- const unsigned char *str = str0;
- const unsigned char *limit = str + length;
- int need_space = 0;
- int is_method = str[0] == '(';
- const unsigned char *next;
-
- /* If printing a method, skip to the return signature and print
- that first. However, there is no return value if this is a
- constructor. */
- if (is_method && ! is_init)
- {
- while (str < limit)
- {
- int ch = *str++;
- if (ch == ')')
- break;
- }
- }
-
- /* If printing a field or an ordinary method, then print the
- "return value" now. */
- if (! is_method || ! is_init)
- {
- next = decode_signature_piece (stream, str, limit, &need_space);
- if (! next)
- {
- error ("unparseable signature: '%s'", str0);
- return;
- }
- }
-
- /* Force the alignment of the first data member. This is
- because the "new" C++ ABI changed the alignment of non-POD
- classes. gcj, however, still uses the "old" alignment. */
- if (is_first_data_member && ! (flags & ACC_STATIC) && ! is_method)
- {
- is_first_data_member = 0;
- print_cxx_classname (out, " __attribute__((aligned(__alignof__( ",
- jcf, jcf->super_class, 1);
- fputs (" )))) ", stream);
- }
-
- /* Now print the name of the thing. */
- if (need_space)
- fputs (" ", stream);
- print_full_cxx_name (stream, jcf, name_index,
- signature_index, is_init, name_override,
- flags);
- }
-}
-
-/* Print the unqualified method name followed by the signature. */
-static void
-print_full_cxx_name (FILE* stream, JCF* jcf, int name_index,
- int signature_index, int is_init,
- const char *name_override, int flags)
-{
- int length = JPOOL_UTF_LENGTH (jcf, signature_index);
- const unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
- const unsigned char *str = str0;
- const unsigned char *limit = str + length;
- int need_space = 0;
- int is_method = str[0] == '(';
- const unsigned char *next;
-
- if (name_override)
- fputs (name_override, stream);
- else if (name_index)
- {
- /* Declare constructors specially. */
- if (is_init)
- print_base_classname (stream, jcf, jcf->this_class);
- else
- print_name (stream, jcf, name_index);
- }
-
- if (flag_jni)
- {
- unsigned char *signature = JPOOL_UTF_DATA (jcf, signature_index);
- int sig_len = JPOOL_UTF_LENGTH (jcf, signature_index);
- if (overloaded_jni_method_exists_p (JPOOL_UTF_DATA (jcf, name_index),
- JPOOL_UTF_LENGTH (jcf, name_index),
- (const char *) signature, sig_len))
- {
- /* If this method is overloaded by another native method,
- then include the argument information in the mangled
- name. */
- unsigned char *limit = signature + sig_len;
- fputs ("__", stream);
- while (signature < limit)
- {
- int ch = UTF8_GET (signature, limit);
- jni_print_char (stream, ch);
- if (ch == ')')
- {
- /* Done. */
- break;
- }
- }
- }
- }
-
- if (is_method)
- {
- /* Have a method or a constructor. Print signature pieces
- until done. */
- fputs (" (", stream);
-
- str = str0 + 1;
-
- /* In JNI mode, add extra arguments. */
- if (flag_jni)
- {
- /* FIXME: it would be nice to know if we are printing a decl
- or a definition, and only print `env' for the latter. */
- fputs ("JNIEnv *env", stream);
-
- fputs ((flags & ACC_STATIC) ? ", jclass" : ", jobject", stream);
-
- if (*str != ')')
- fputs (", ", stream);
- }
-
- while (str < limit && *str != ')')
- {
- next = decode_signature_piece (stream, str, limit, &need_space);
- if (! next)
- {
- error ("unparseable signature: '%s'", str0);
- return;
- }
-
- if (next < limit && *next != ')')
- fputs (", ", stream);
- str = next;
- }
-
- fputs (")", stream);
- }
-}
-
-/* This is a helper for print_stub_or_jni. */
-static void
-print_name_for_stub_or_jni (FILE *stream, JCF *jcf, int name_index,
- int signature_index, int is_init,
- const char *name_override, int flags)
-{
- const char *const prefix = flag_jni ? "Java_" : "";
- print_cxx_classname (stream, prefix, jcf, jcf->this_class, 1);
- fputs (flag_jni ? "_" : "::", stream);
- print_full_cxx_name (stream, jcf, name_index,
- signature_index, is_init, name_override,
- flags);
-}
-
-static void
-print_stub_or_jni (FILE* stream, JCF* jcf, int name_index,
- int signature_index, int is_init,
- const char *name_override, int flags)
-{
- if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
- {
- fprintf (stream, "<not a UTF8 constant>");
- found_error = 1;
- }
- else
- {
- int length = JPOOL_UTF_LENGTH (jcf, signature_index);
- const unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
- const unsigned char *str = str0;
- const unsigned char *limit = str + length;
- int need_space = 0;
- int is_method = str[0] == '(';
- const unsigned char *next;
-
- /* Don't print fields in the JNI case. */
- if (! is_method && flag_jni)
- return;
-
- if (flag_jni && ! stubs)
- fputs ("JNIEXPORT ", stream);
-
- /* If printing a method, skip to the return signature and print
- that first. However, there is no return value if this is a
- constructor. */
- if (is_method && ! is_init)
- {
- while (str < limit)
- {
- int ch = *str++;
- if (ch == ')')
- break;
- }
- }
-
- /* If printing a field or an ordinary method, then print the
- "return value" now. Note that a constructor can't be native,
- so we don't bother checking this in the JNI case. */
- if (! is_method || ! is_init)
- {
- next = decode_signature_piece (stream, str, limit, &need_space);
- if (! next)
- {
- error ("unparseable signature: '%s'", str0);
- return;
- }
- }
-
- /* When printing a JNI header we need to respect the space. In
- other cases we're just going to insert a newline anyway. */
- fputs (need_space && ! stubs ? " " : "\n", stream);
-
- if (flag_jni && ! stubs)
- fputs ("JNICALL ", stream);
-
- /* Now print the name of the thing. */
- print_name_for_stub_or_jni (stream, jcf, name_index,
- signature_index, is_init, name_override,
- flags);
-
- /* Print the body. */
- if (stubs)
- {
- if (flag_jni)
- fputs ("\n{\n (*env)->FatalError (env, \"", stream);
- else
- fputs ("\n{\n throw new ::java::lang::UnsupportedOperationException (JvNewStringLatin1 (\"", stream);
- print_name_for_stub_or_jni (stream, jcf, name_index,
- signature_index, is_init,
- name_override,
- flags);
- fprintf (stream, " not implemented\")%s;\n}\n\n",
- flag_jni ? "" : ")");
- }
- }
-}
-
-static void
-print_mangled_classname (FILE *stream, JCF *jcf, const char *prefix, 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 (FILE *stream, const char *prefix,
- JCF *jcf, int index, int add_scope)
-{
- int name_index = JPOOL_USHORT1 (jcf, index);
- int len, c;
- const 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);
-
- /* Print a leading "::" so we look in the right namespace. */
- if (! flag_jni && ! stubs && add_scope)
- fputs ("::", stream);
-
- while (s < limit)
- {
- c = UTF8_GET (s, limit);
- if (c == '/')
- fputs (flag_jni ? "_" : "::", stream);
- else
- jni_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 const unsigned char *
-super_class_name (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);
- const unsigned char *supername =
- JPOOL_UTF_DATA (derived_jcf, supername_index);
-
- if (len)
- *len = supername_length;
-
- return supername;
-}
-
-static void
-handle_inner_classes (int count)
-{
- int i;
-
- if (out && ! flag_jni && ! stubs && count > 0)
- fprintf (out, "\n");
-
- for (i = 0; i < count; ++i)
- {
- JCF_u2 inner_info_index = JCF_readu2 (current_jcf);
-
- /* There are a few more values here, but we don't care about
- them. The (void) cast is apparently the only way to avoid a
- warning here. */
- (void) JCF_readu2 (current_jcf);
- (void) JCF_readu2 (current_jcf);
- (void) JCF_readu2 (current_jcf);
-
- if (out && ! flag_jni && ! stubs)
- {
- print_mangled_classname (out, current_jcf, " friend class ",
- inner_info_index);
- fprintf (out, ";\n");
- }
- }
-}
-
-
-
-/* We keep track of all the `#include's we generate, so we can avoid
- duplicates. */
-struct include
-{
- char *name;
- struct include *next;
-};
-
-/* List of all includes. */
-static struct include *all_includes = NULL;
-
-/* Generate a #include. */
-static void
-print_include (FILE *out, const unsigned char *utf8, int len)
-{
- struct include *incl;
-
- if (! out)
- return;
-
- if (len == -1)
- len = strlen ((const char *) utf8);
-
- for (incl = all_includes; incl; incl = incl->next)
- {
- /* We check the length because we might have a proper prefix. */
- if (len == (int) strlen (incl->name)
- && ! strncmp (incl->name, (const char *) utf8, len))
- return;
- }
-
- incl = XNEW (struct include);
- incl->name = XNEWVEC (char, len + 1);
- strncpy (incl->name, (const char *) utf8, len);
- incl->name[len] = '\0';
- incl->next = all_includes;
- all_includes = incl;
-
- fputs ("#include <", out);
- jcf_print_utf8_replace (out, utf8, len,
- '/',
- flag_jni ? '_' : '/');
- fputs (".h>\n", out);
-}
-
-
-
-/* This is used to represent part of a package or class name. */
-struct namelet
-{
- /* The text of this part of the name. */
- char *name;
- /* True if this represents a class. */
- int is_class;
- /* Linked list of all classes and packages inside this one. */
- struct namelet *subnamelets;
- /* Pointer to next sibling. */
- struct namelet *next;
-};
-
-static void add_namelet (const unsigned char *, const unsigned char *,
- struct namelet *);
-static void print_namelet (FILE *, struct namelet *, int);
-
-/* The special root namelet. */
-static struct namelet root =
-{
- NULL,
- 0,
- NULL,
- NULL
-};
-
-/* This extracts the next name segment from the full UTF-8 encoded
- package or class name and links it into the tree. It does this
- recursively. */
-static void
-add_namelet (const unsigned char *name, const unsigned char *name_limit,
- struct namelet *parent)
-{
- const unsigned char *p;
- struct namelet *n = NULL, *np;
-
- /* We want to skip the standard namespaces that we assume the
- runtime already knows about. We only do this at the top level,
- though, hence the check for `root'. */
- if (parent == &root)
- {
-#define JAVALANG "java/lang/"
-#define JAVAIO "java/io/"
-#define JAVAUTIL "java/util/"
- if ((name_limit - name >= (int) sizeof (JAVALANG) - 1
- && ! strncmp ((const char *) name, JAVALANG, sizeof (JAVALANG) - 1))
- || (name_limit - name >= (int) sizeof (JAVAUTIL) - 1
- && ! strncmp ((const char *) name, JAVAUTIL, sizeof (JAVAUTIL) - 1))
- || (name_limit - name >= (int) sizeof (JAVAIO) - 1
- && ! strncmp ((const char *) name, JAVAIO, sizeof (JAVAIO) - 1)))
- return;
- }
-
- for (p = name; p < name_limit && *p != '/'; ++p)
- ;
-
- /* Search for this name beneath the PARENT node. */
- for (np = parent->subnamelets; np != NULL; np = np->next)
- {
- /* We check the length because we might have a proper prefix. */
- if ((int) strlen (np->name) == p - name &&
- ! strncmp ((const char *) name, np->name, p - name))
- {
- n = np;
- break;
- }
- }
-
- if (n == NULL)
- {
- n = XNEW (struct namelet);
- n->name = XNEWVEC (char, p - name + 1);
- strncpy (n->name, (const char *) name, p - name);
- n->name[p - name] = '\0';
- n->is_class = (p == name_limit);
- n->subnamelets = NULL;
- n->next = parent->subnamelets;
- parent->subnamelets = n;
- }
-
- /* We recurse if there is more text, and if the trailing piece does
- not represent an inner class. */
- if (p < name_limit)
- add_namelet (p + 1, name_limit, n);
-}
-
-/* Print a single namelet. Destroys namelets while printing. */
-static void
-print_namelet (FILE *out, struct namelet *name, int depth)
-{
- int i, term = 0;
- struct namelet *c;
-
- if (name->name)
- {
- for (i = 0; i < depth; ++i)
- fputc (' ', out);
- fprintf (out, "%s %s", name->is_class ? "class" : "namespace",
- name->name);
- if (name->is_class && name->subnamelets == NULL)
- fputs (";\n", out);
- else
- {
- term = 1;
- fputs ("\n", out);
- for (i = 0; i < depth; ++i)
- fputc (' ', out);
- fputs ("{\n", out);
- }
- }
-
- c = name->subnamelets;
- while (c != NULL)
- {
- struct namelet *next = c->next;
- print_namelet (out, c, depth + 2);
- c = next;
- }
- name->subnamelets = NULL;
-
- if (name->name)
- {
- if (term)
- {
- for (i = 0; i < depth; ++i)
- fputc (' ', out);
- fputs ("}\n", out);
- /* Only print a `;' when printing a class. C++ is evil. */
- if (name->is_class)
- fputs (";", out);
- }
-
- free (name->name);
- free (name);
- }
-}
-
-/* This is called to add some classes to the list of classes for which
- we need decls. The signature argument can be a function
- signature. */
-static void
-add_class_decl (FILE *out, JCF *jcf, JCF_u2 signature)
-{
- const unsigned char *s = JPOOL_UTF_DATA (jcf, signature);
- int len = JPOOL_UTF_LENGTH (jcf, signature);
- int i;
-
- for (i = 0; i < len; ++i)
- {
- int start;
-
- /* If we see an array, then we include the array header. */
- if (s[i] == '[')
- {
- print_include (out, (const unsigned char *) "gcj/array", -1);
- continue;
- }
-
- /* We're looking for `L<stuff>;' -- everything else is
- ignorable. */
- if (s[i] != 'L')
- continue;
-
- for (start = ++i; i < len && s[i] != ';'; ++i)
- ;
-
- add_namelet (&s[start], &s[i], &root);
- }
-}
-
-/* Print declarations for all classes required by this class. Any
- class or package in the `java' package is assumed to be handled
- statically in libjava; we don't generate declarations for these.
- This makes the generated headers a bit easier to read. */
-static void
-print_class_decls (FILE *out, JCF *jcf, int self)
-{
- /* Make sure to always add the current class to the list of things
- that should be declared. */
- int name_index = JPOOL_USHORT1 (jcf, self);
- int len;
- const unsigned char *s;
-
- s = JPOOL_UTF_DATA (jcf, name_index);
- len = JPOOL_UTF_LENGTH (jcf, name_index);
- add_namelet (s, s + len, &root);
-
- if (root.subnamelets)
- {
- fputs ("extern \"Java\"\n{\n", out);
- /* We use an initial offset of 0 because the root namelet
- doesn't cause anything to print. */
- print_namelet (out, &root, 0);
- fputs ("}\n\n", out);
- }
-}
-
-
-
-static void
-process_file (JCF *jcf, FILE *out)
-{
- int code, i;
- uint32 field_start, method_end, method_start;
-
- current_jcf = jcf;
-
- last_access = -1;
-
- if (jcf_parse_preamble (jcf) != 0)
- {
- error ("Not a valid Java .class file.");
- return;
- }
-
- /* Parse and possibly print constant pool */
- code = jcf_parse_constant_pool (jcf);
- if (code != 0)
- {
- error ("error while parsing constant pool");
- return;
- }
- code = verify_constant_pool (jcf);
- if (code > 0)
- {
- error ("error in constant pool entry #%d", code);
- return;
- }
-
- jcf_parse_class (jcf);
-
- if (written_class_count++ == 0 && out)
- {
- const char *cstart, *cstart2, *mode, *cend, *what, *jflag;
- if (flag_jni)
- {
- cstart = "/*";
- cstart2 = " ";
- cend = " */";
- mode = "";
- what = "JNI";
- jflag = " -jni";
- }
- else
- {
- cstart = "//";
- cstart2 = "//";
- cend = "";
- mode = " -*- c++ -*-";
- what = "CNI";
- jflag = "";
- }
-
- if (! stubs)
- fprintf (out, "%s DO NOT EDIT THIS FILE - it is machine generated%s%s\n\n",
- cstart, mode, cend);
- else
- {
- fprintf (out, "%s This file was created by `" TOOLNAME " -stubs%s'.%s\n\
-%s\n\
-%s This file is intended to give you a head start on implementing native\n\
-%s methods using %s.\n\
-%s Be aware: running `" TOOLNAME " -stubs %s' once more for this class may\n\
-%s overwrite any edits you have made to this file.%s\n\n",
- cstart, jflag, mode,
- cstart2,
- cstart2,
- cstart2,
- what,
- cstart2,
- jflag,
- cstart2,
- cend);
- }
- }
-
- if (out)
- {
- if (! stubs)
- {
- 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 (flag_jni)
- {
- fprintf (out, "#include <jni.h>\n\n");
- fprintf (out, "#ifdef __cplusplus\n");
- fprintf (out, "extern \"C\"\n");
- fprintf (out, "{\n");
- fprintf (out, "#endif\n");
- }
- else
- {
- /* We do this to ensure that inline methods won't be
- `outlined' by g++. This works as long as method and
- fields are not added by the user. */
- fprintf (out, "#pragma interface\n");
-
- if (jcf->super_class)
- {
- int super_length;
- const unsigned char *supername =
- super_class_name (jcf, &super_length);
-
- fputs ("\n", out);
- print_include (out, supername, super_length);
- }
- }
- }
- else
- {
- /* Strip off the ".class" portion of the name when printing
- the include file name. */
- char *name;
- int i, len = strlen (jcf->classname);
- if (len > 6 && ! strcmp (&jcf->classname[len - 6], ".class"))
- len -= 6;
- /* Turn the class name into a file name. */
- name = XNEWVEC (char, len + 1);
- for (i = 0; i < len; ++i)
- name[i] = jcf->classname[i] == '.' ? '/' : jcf->classname[i];
- name[i] = '\0';
- print_include (out, (const unsigned char *) name, len);
- free (name);
-
- if (! flag_jni)
- {
- print_include (out, (const unsigned char *) "gcj/cni", -1);
- print_include (out, (const unsigned char *) "java/lang/UnsupportedOperationException",
- -1);
- }
- }
- }
-
- /* We want to parse the methods first. But we need to find where
- they start. So first we skip the fields, then parse the methods.
- Then we parse the fields and skip the methods. This is ugly, but
- not too bad since we need two full passes to get class decl
- information anyway. */
- field_pass = 0;
- field_start = JCF_TELL (jcf);
- jcf_parse_fields (jcf);
-
- method_start = JCF_TELL (jcf);
- method_pass = 0;
- jcf_parse_methods (jcf);
-
- if (out)
- fputs ("\n", out);
-
- if (out && ! flag_jni)
- {
- if (! stubs)
- print_class_decls (out, jcf, jcf->this_class);
-
- for (i = 0; i < prepend_count; ++i)
- fprintf (out, "%s\n", prepend_specs[i]);
- if (prepend_count > 0)
- fputc ('\n', out);
-
- if (! stubs)
- {
- if (! print_cxx_classname (out, "class ", jcf,
- jcf->this_class, 0))
- {
- error ("class is of array type\n");
- return;
- }
- if (jcf->super_class)
- {
- if (! print_cxx_classname (out, " : public ",
- jcf, jcf->super_class, 1))
- {
- error ("base class is of array type");
- return;
- }
- }
-
- fputs ("\n{\n", out);
- }
- }
-
- /* Now go back for second pass over methods and fields. */
- is_first_data_member = 1;
-
- JCF_SEEK (jcf, method_start);
- method_pass = 1;
- jcf_parse_methods (jcf);
- method_end = JCF_TELL (jcf);
-
- field_pass = 1;
- JCF_SEEK (jcf, field_start);
- jcf_parse_fields (jcf);
- JCF_SEEK (jcf, method_end);
-
- jcf_parse_final_attributes (jcf);
-
- if (out && ! stubs)
- {
- if (flag_jni)
- {
- fprintf (out, "\n#ifdef __cplusplus\n");
- fprintf (out, "}\n");
- fprintf (out, "#endif\n");
- }
- else
- {
- /* 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]);
-
- /* Generate an entry for the class object. */
- generate_access (out, ACC_PUBLIC);
- fprintf (out, "\n static ::java::lang::Class class$;\n");
-
- fputs ("}", out);
-
- if (jcf->access_flags & ACC_INTERFACE)
- fputs (" __attribute__ ((java_interface))", out);
-
- 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");
- }
-}
-
-
-
-/* This is used to mark options with no short value. */
-#define LONG_OPT(Num) ((Num) + 128)
-
-#define OPT_classpath LONG_OPT (0)
-#define OPT_CLASSPATH OPT_classpath
-#define OPT_bootclasspath LONG_OPT (1)
-#define OPT_extdirs LONG_OPT (2)
-#define OPT_HELP LONG_OPT (3)
-#define OPT_TEMP LONG_OPT (4)
-#define OPT_VERSION LONG_OPT (5)
-#define OPT_PREPEND LONG_OPT (6)
-#define OPT_FRIEND LONG_OPT (7)
-#define OPT_ADD LONG_OPT (8)
-#define OPT_APPEND LONG_OPT (9)
-#define OPT_M LONG_OPT (10)
-#define OPT_MM LONG_OPT (11)
-#define OPT_MG LONG_OPT (12)
-#define OPT_MD LONG_OPT (13)
-#define OPT_MMD LONG_OPT (14)
-#define OPT_FORCE LONG_OPT (15)
-#define OPT_OLD LONG_OPT (16)
-#define OPT_TRACE LONG_OPT (17)
-
-static const struct option options[] =
-{
- { "classpath", required_argument, NULL, OPT_classpath },
- { "bootclasspath", required_argument, NULL, OPT_bootclasspath },
- { "extdirs", required_argument, NULL, OPT_extdirs },
- { "CLASSPATH", required_argument, NULL, OPT_CLASSPATH },
- { "help", no_argument, NULL, OPT_HELP },
- { "stubs", no_argument, &stubs, 1 },
- { "td", required_argument, NULL, OPT_TEMP },
- { "verbose", no_argument, NULL, 'v' },
- { "version", no_argument, NULL, OPT_VERSION },
- { "prepend", required_argument, NULL, OPT_PREPEND },
- { "friend", required_argument, NULL, OPT_FRIEND },
- { "add", required_argument, NULL, OPT_ADD },
- { "append", required_argument, NULL, OPT_APPEND },
- { "M", no_argument, NULL, OPT_M },
- { "MM", no_argument, NULL, OPT_MM },
- { "MG", no_argument, NULL, OPT_MG },
- { "MD", no_argument, NULL, OPT_MD },
- { "MMD", no_argument, NULL, OPT_MMD },
- { "jni", no_argument, &flag_jni, 1 },
- { "force", no_argument, NULL, OPT_FORCE },
- /* If the output file should be named "ld" then a space is needed
- between -o and its argument, ld. */
- { "old", no_argument, NULL, OPT_OLD },
- { "trace", no_argument, NULL, OPT_TRACE },
- { NULL, required_argument, NULL, 'J' },
- { NULL, no_argument, NULL, 0 }
-};
-
-static void
-usage (void)
-{
- fprintf (stderr, _("Try '" TOOLNAME " --help' for more information.\n"));
- exit (1);
-}
-
-static void
-help (void)
-{
- printf (_("Usage: " TOOLNAME " [OPTION]... CLASS...\n\n"));
- printf (_("Generate C or C++ header files from .class files\n\n"));
- printf (_(" -stubs Generate an implementation stub file\n"));
- printf (_(" -jni Generate a JNI header or stub\n"));
- printf (_(" -force Always overwrite output files\n"));
- printf (_(" -old Unused compatibility option\n"));
- printf (_(" -trace Unused compatibility option\n"));
- printf (_(" -J OPTION Unused compatibility option\n"));
- printf ("\n");
- printf (_(" -add TEXT Insert TEXT into class body\n"));
- printf (_(" -append TEXT Insert TEXT after class declaration\n"));
- printf (_(" -friend TEXT Insert TEXT as 'friend' declaration\n"));
- printf (_(" -prepend TEXT Insert TEXT before start of class\n"));
- printf ("\n");
- printf (_(" --classpath PATH Set path to find .class files\n"));
- printf (_(" -IDIR Append directory to class path\n"));
- printf (_(" --bootclasspath PATH Override built-in class path\n"));
- printf (_(" --extdirs PATH Set extensions directory path\n"));
- printf (_(" -d DIRECTORY Set output directory name\n"));
- printf (_(" -o FILE Set output file name\n"));
- printf (_(" -td DIRECTORY Set temporary directory name\n"));
- printf ("\n");
- printf (_(" --help Print this help, then exit\n"));
- printf (_(" --version Print version number, then exit\n"));
- printf (_(" -v, --verbose Print extra information while running\n"));
- printf ("\n");
- printf (_(" -M Print all dependencies to stdout;\n"
- " suppress ordinary output\n"));
- printf (_(" -MM Print non-system dependencies to stdout;\n"
- " suppress ordinary output\n"));
- printf (_(" -MD Print all dependencies to stdout\n"));
- printf (_(" -MMD Print non-system dependencies to stdout\n"));
- /* We omit -MG until it is implemented. */
- printf ("\n");
- printf (_("For bug reporting instructions, please see:\n"
- "%s.\n"), bug_report_url);
- exit (0);
-}
-
-static void
-version (void)
-{
- printf (TOOLNAME " (GCC) %s\n\n", version_string);
- printf ("Copyright %s 2006 Free Software Foundation, Inc.\n", _("(C)"));
- printf (_("This is free software; see the source for copying conditions. There is NO\n"
- "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
- exit (0);
-}
-
-int
-main (int argc, char** argv)
-{
- JCF jcf;
- int argi;
- char *output_file = NULL;
- int emit_dependencies = 0, suppress_output = 0;
- int opt;
- int local_found_error;
-
- /* Unlock the stdio streams. */
- unlock_std_streams ();
-
- gcc_init_libintl ();
-
- if (argc <= 1)
- {
- error ("no classes specified");
- usage ();
- }
-
- jcf_path_init ();
-
- /* We use getopt_long_only to allow single `-' long options. For
- some of our options this is more natural. */
- while ((opt = getopt_long_only (argc, argv, "J:I:d:o:v", options, NULL)) != -1)
- {
- switch (opt)
- {
- case 0:
- /* Already handled. */
- break;
-
- case 'o':
- output_file = optarg;
- break;
-
- case 'd':
- output_directory = optarg;
- break;
-
- case 'I':
- jcf_path_include_arg (optarg);
- break;
-
- case 'v':
- verbose++;
- break;
-
- case OPT_classpath:
- jcf_path_classpath_arg (optarg);
- break;
-
- case OPT_bootclasspath:
- jcf_path_bootclasspath_arg (optarg);
- break;
-
- case OPT_extdirs:
- jcf_path_extdirs_arg (optarg);
- break;
-
- case OPT_HELP:
- help ();
- break;
-
- case OPT_TEMP:
- temp_directory = optarg;
- break;
-
- case OPT_VERSION:
- version ();
- break;
-
- case OPT_PREPEND:
- if (prepend_count == 0)
- prepend_specs = XNEWVEC (char *, argc);
- prepend_specs[prepend_count++] = optarg;
- break;
-
- case OPT_FRIEND:
- if (friend_count == 0)
- friend_specs = XNEWVEC (char *, argc);
- friend_specs[friend_count++] = optarg;
- break;
-
- case OPT_ADD:
- if (add_count == 0)
- add_specs = XNEWVEC (char *, argc);
- add_specs[add_count++] = optarg;
- break;
-
- case OPT_APPEND:
- if (append_count == 0)
- append_specs = XNEWVEC (char *, argc);
- append_specs[append_count++] = optarg;
- break;
-
- case OPT_M:
- emit_dependencies = 1;
- suppress_output = 1;
- jcf_dependency_init (1);
- break;
-
- case OPT_MM:
- emit_dependencies = 1;
- suppress_output = 1;
- jcf_dependency_init (0);
- break;
-
- case OPT_MG:
- error ("'-MG' option is unimplemented");
- exit (1);
-
- case OPT_MD:
- emit_dependencies = 1;
- jcf_dependency_init (1);
- break;
-
- case OPT_MMD:
- emit_dependencies = 1;
- jcf_dependency_init (0);
- break;
-
- case OPT_FORCE:
- break;
-
- case OPT_OLD:
- break;
-
- case OPT_TRACE:
- break;
-
- case 'J':
- /* Ignore -J options. */
- break;
-
- default:
- usage ();
- break;
- }
- }
-
- if (optind == argc)
- {
- error ("no classes specified");
- usage ();
- }
-
- jcf_path_seal (verbose);
-
- if (output_file && emit_dependencies)
- {
- error ("can't specify both -o and -MD");
- exit (1);
- }
-
- local_found_error = 0;
- for (argi = optind; argi < argc; argi++)
- {
- char *classname = argv[argi];
- char *current_output_file = NULL;
- const char *classfile_name;
-
- /* We reset the error state here so that we can detect errors
- that occur when processing this file, so the output can be
- unlinked if need be. */
- found_error = 0;
-
- if (verbose)
- printf (_("Processing %s\n"), classname);
- if (! output_file)
- jcf_dependency_reset ();
- classfile_name = find_class (classname, strlen (classname), &jcf, 0);
- if (classfile_name == NULL)
- {
- error ("%s: no such class", classname);
- exit (1);
- }
- if (verbose)
- printf (_("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 = XNEWVEC (char, dir_len + classname_length + 5);
- 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 = '/';
- if (flag_jni && ch == '/')
- ch = '_';
- current_output_file[dir_len++] = ch;
- }
- if (emit_dependencies)
- {
- if (suppress_output)
- {
- jcf_dependency_set_dep_file ("-");
- out = NULL;
- }
- else
- {
- /* We use `.hd' and not `.d' to avoid clashes with
- dependency tracking from straight compilation. */
- strcpy (current_output_file + dir_len, ".hd");
- jcf_dependency_set_dep_file (current_output_file);
- }
- }
- strcpy (current_output_file + dir_len,
- stubs ? (flag_jni ? ".c" : ".cc") : ".h");
- jcf_dependency_set_target (current_output_file);
- if (! suppress_output)
- {
- out = fopen (current_output_file, "w");
- if (out == NULL)
- {
- perror (current_output_file);
- exit (1);
- }
- }
- }
- free_method_name_list ();
- process_file (&jcf, out);
- JCF_FINISH (&jcf);
-
- /* If we found an error and we're writing to a real file,
- delete it. */
- if (found_error && ! suppress_output && current_output_file != NULL
- && strcmp (current_output_file, "-"))
- unlink (current_output_file);
-
- if (current_output_file != output_file)
- free (current_output_file);
- jcf_dependency_write ();
-
- local_found_error |= found_error;
- }
-
- if (out != NULL && out != stdout)
- fclose (out);
-
- return local_found_error;
-}