summaryrefslogtreecommitdiff
path: root/gcc/java/gjavah.c
diff options
context:
space:
mode:
authortromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4>1999-02-24 13:47:39 +0000
committertromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4>1999-02-24 13:47:39 +0000
commit0586b957aac832640fd0020548c04a805deda54c (patch)
treed69df26a5c83842fd59c5587dfe4b063f95c6466 /gcc/java/gjavah.c
parente9b8fedee76e429e59b6b4f6f0fe0f698b676448 (diff)
downloadgcc-0586b957aac832640fd0020548c04a805deda54c.tar.gz
* gjavah.c (struct namelet): New structure.
(add_namelet): New function. (print_namelet): New function. (print_class_decls): Use add_namelet and print_namelet to generate namespaces and not classes. (method_printed): New global. (HANDLE_END_METHOD): Examine method_printed. (print_method_info): Set method_printed when required. Print error if function to be ignored is marked virtual. Handle $finit$ method. (METHOD_IS_FINAL): New macro. (print_field_info): Use it. (HANDLE_METHOD): Clear method_printed. (method_pass): New global. (HANDLE_END_FIELD): Call add_class_decl on the first pass. (process_file): Do two passes over both fields and methods. (HANDLE_METHOD): Examine method_pass. (root): New global. (add_class_decl): New function. (print_class_decls): Don't scan over entire constant pool. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@25403 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/java/gjavah.c')
-rw-r--r--gcc/java/gjavah.c312
1 files changed, 261 insertions, 51 deletions
diff --git a/gcc/java/gjavah.c b/gcc/java/gjavah.c
index df47777c24c..986ed1ff92f 100644
--- a/gcc/java/gjavah.c
+++ b/gcc/java/gjavah.c
@@ -81,6 +81,11 @@ static JCF_u2 last_access;
#define ACC_VISIBILITY (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED)
+/* 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)))
+
/* 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
@@ -97,6 +102,7 @@ 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, const char *));
static void decompile_method PROTO ((FILE *, JCF *, int));
+static void add_class_decl PROTO ((FILE *, JCF *, JCF_u2));
JCF_u2 current_field_name;
JCF_u2 current_field_value;
@@ -107,31 +113,47 @@ JCF_u2 current_field_flags;
( current_field_name = (NAME), current_field_signature = (SIGNATURE), \
current_field_flags = (ACCESS_FLAGS), current_field_value = 0)
-/* We pass over fields twice. The first time we just note the start
- of the methods. Then we go back and parse the fields for real.
- This is ugly. */
+/* 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;
-
-#define HANDLE_END_FIELD() \
- if (out && field_pass) print_field_info (out, jcf, current_field_name, \
- current_field_signature, \
- current_field_flags);
+/* 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) \
+ print_field_info (out, jcf, current_field_name, \
+ current_field_signature, \
+ current_field_flags); \
+ } \
+ else \
+ 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;
-#define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
- if (out) { decompiled = 0; \
- print_method_info (out, jcf, NAME, SIGNATURE, ACCESS_FLAGS); \
- }
+static int method_printed = 0;
+#define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
+ if (method_pass) \
+ { \
+ decompiled = 0; method_printed = 0; \
+ if (out) \
+ print_method_info (out, jcf, NAME, SIGNATURE, ACCESS_FLAGS); \
+ } \
+ else \
+ add_class_decl (out, jcf, SIGNATURE);
#define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
if (out && method_declared) decompile_method (out, jcf, CODE_LENGTH);
static int decompiled = 0;
#define HANDLE_END_METHOD() \
- if (out) fputs (decompiled ? "\n" : ";\n", out);
+ if (out && method_printed) fputs (decompiled ? "\n" : ";\n", out);
#include "jcf-reader.c"
@@ -426,13 +448,24 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
fprintf (stream, "<not a UTF8 constant>");
str = JPOOL_UTF_DATA (jcf, name_index);
length = JPOOL_UTF_LENGTH (jcf, name_index);
- if (str[0] == '<')
+ if (str[0] == '<' || str[0] == '$')
{
- /* Ignore internally generated methods like <clinit>. However,
- treat <init> as a constructor. */
+ /* Ignore internally generated methods like <clinit> and
+ $finit$. However, treat <init> as a constructor. */
if (! utf8_cmp (str, length, "<init>"))
is_init = 1;
- else
+ 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;
}
else
@@ -455,20 +488,22 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
after it in the vtbl). So we give it a dummy name instead. */
if (! utf8_cmp (str, length, "delete"))
{
- /* If the method is static, we can safely skip it. If we don't
- skip it then we'll have problems since the mangling will be
- wrong. FIXME. */
- if ((flags & ACC_STATIC))
+ /* If the method is static or final, we can safely skip it. If
+ we don't skip it then we'll have problems since the mangling
+ will be wrong. FIXME. */
+ if (METHOD_IS_FINAL (jcf->access_flags, flags)
+ || (flags & ACC_STATIC))
return;
override = "__dummy_delete";
}
+ method_printed = 1;
generate_access (stream, flags);
fputs (" ", out);
if ((flags & ACC_STATIC))
fputs ("static ", out);
- else if (! (flags & ACC_FINAL) && ! (jcf->access_flags & ACC_FINAL))
+ else if (! METHOD_IS_FINAL (jcf->access_flags, flags))
{
/* Don't print `virtual' if we have a constructor. */
if (! is_init)
@@ -795,39 +830,210 @@ super_class_name (derived_jcf, len)
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. */
+
+
+/* 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;
+};
+
+/* 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
-print_class_decls (out, jcf)
+add_namelet (name, name_limit, parent)
+ unsigned char *name, *name_limit;
+ struct namelet *parent;
+{
+ unsigned char *p;
+ struct namelet *n = NULL, *np;
+
+ for (p = name; p < name_limit && *p != '/' && *p != '$'; ++p)
+ ;
+
+ /* Search for this name beneath the PARENT node. */
+ for (np = parent->subnamelets; np != NULL; np = np->next)
+ {
+ if (! strncmp (name, np->name, p - name))
+ {
+ n = np;
+ break;
+ }
+ }
+
+ if (n == NULL)
+ {
+ n = (struct namelet *) malloc (sizeof (struct namelet));
+ n->name = malloc (p - name + 1);
+ strncpy (n->name, name, p - name);
+ n->name[p - name] = '\0';
+ n->is_class = (p == name_limit || *p == '$');
+ 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 && *p != '$')
+ add_namelet (p + 1, name_limit, n);
+}
+
+/* Print a single namelet. Destroys namelets while printing. */
+static void
+print_namelet (out, name, depth)
+ 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;
+ }
+
+ if (name->name)
+ {
+ if (term)
+ {
+ for (i = 0; i < depth; ++i)
+ fputc (' ', out);
+ fputs ("};\n", 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 (out, jcf, signature)
FILE *out;
JCF *jcf;
+ JCF_u2 signature;
{
- int i, seen_one = 0;
+ unsigned char *s = JPOOL_UTF_DATA (jcf, signature);
+ int len = JPOOL_UTF_LENGTH (jcf, signature);
+ int i;
- for (i = 1; i < JPOOL_SIZE (jcf); ++i)
+ for (i = 0; i < len; ++i)
{
- int kind = JPOOL_TAG (jcf, i);
- if (kind == CONSTANT_Class)
+ int start;
+ /* We're looking for `L<stuff>;' -- everything else is
+ ignorable. */
+ if (s[i] != 'L')
+ continue;
+ for (start = ++i; i < len && s[i] != ';'; ++i)
+ {
+ if (s[i] == '$' && out)
+ {
+ /* If this class represents an inner class, then
+ generate a `#include' for the outer class. */
+ fputs ("#include <", out);
+ jcf_print_utf8 (out, &s[start], i - start);
+ fputs (">\n", out);
+ }
+ }
+
+#define JAVALANG "java/lang/"
+#define JAVAIO "java/io/"
+#define JAVAUTIL "java/util/"
+ if ((i - start >= sizeof (JAVALANG) - 1
+ && ! strncmp (&s[start], JAVALANG, sizeof (JAVALANG) - 1))
+ || (i - start >= sizeof (JAVAUTIL) - 1
+ && ! strncmp (&s[start], JAVAUTIL, sizeof (JAVAUTIL) - 1))
+ || (i - start >= sizeof (JAVAIO) - 1
+ && ! strncmp (&s[start], JAVAIO, sizeof (JAVAIO) - 1)))
{
- if (print_cxx_classname (out, "class ", jcf, i))
- fputs (";\n", out);
- seen_one = 1;
+ /* Skip all the standard `java.' classes. */
+ continue;
}
+
+ 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 (out, jcf, self)
+ 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;
+ unsigned char *s;
+
+ s = JPOOL_UTF_DATA (jcf, name_index);
+ len = JPOOL_UTF_LENGTH (jcf, name_index);
+ add_namelet (s, s + len, &root);
- if (seen_one)
- fputs ("\n", out);
+ 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
DEFUN(process_file, (jcf, out),
JCF *jcf AND FILE *out)
{
int code, i;
- uint32 field_start, method_end;
+ uint32 field_start, method_end, method_start;
current_jcf = main_jcf = jcf;
@@ -895,9 +1101,22 @@ DEFUN(process_file, (jcf, out),
fputs ("\n", out);
}
+ /* 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)
{
- print_class_decls (out, jcf);
+ print_class_decls (out, jcf, jcf->this_class);
for (i = 0; i < prepend_count; ++i)
fprintf (out, "%s\n", prepend_specs[i]);
@@ -923,18 +1142,9 @@ DEFUN(process_file, (jcf, out),
if (out)
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. */
- /* We want to parse the methods first. But we need to find where
- they start. So first we skip the fields, then parse the
- methods. Then we parse the fields and skip the methods. FIXME:
- this is ugly. */
- field_pass = 0;
- field_start = JCF_TELL (jcf);
- jcf_parse_fields (jcf);
-
+ /* Now go back for second pass over methods and fields. */
+ JCF_SEEK (jcf, method_start);
+ method_pass = 1;
jcf_parse_methods (jcf);
method_end = JCF_TELL (jcf);