Commit bdb59aec by Tom Tromey Committed by Tom Tromey

gjavah.c (struct namelet): New structure.

	* 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.

From-SVN: r25403
parent 46f40127
1999-02-24 Tom Tromey <tromey@cygnus.com>
* 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.
1999-02-23 Tom Tromey <tromey@cygnus.com> 1999-02-23 Tom Tromey <tromey@cygnus.com>
* jvspec.c (lang_specific_driver): Recognize -fsyntax-only and * jvspec.c (lang_specific_driver): Recognize -fsyntax-only and
......
...@@ -81,6 +81,11 @@ static JCF_u2 last_access; ...@@ -81,6 +81,11 @@ static JCF_u2 last_access;
#define ACC_VISIBILITY (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED) #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 /* 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. */ us determine if a method name and a field name are in conflict. */
struct method_name struct method_name
...@@ -97,6 +102,7 @@ static void print_field_info PROTO ((FILE *, JCF*, int, int, JCF_u2)); ...@@ -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_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 print_c_decl PROTO ((FILE*, JCF*, int, int, JCF_u2, int, const char *));
static void decompile_method PROTO ((FILE *, JCF *, int)); 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_name;
JCF_u2 current_field_value; JCF_u2 current_field_value;
...@@ -107,31 +113,47 @@ JCF_u2 current_field_flags; ...@@ -107,31 +113,47 @@ JCF_u2 current_field_flags;
( current_field_name = (NAME), current_field_signature = (SIGNATURE), \ ( current_field_name = (NAME), current_field_signature = (SIGNATURE), \
current_field_flags = (ACCESS_FLAGS), current_field_value = 0) current_field_flags = (ACCESS_FLAGS), current_field_value = 0)
/* We pass over fields twice. The first time we just note the start /* We pass over fields twice. The first time we just note the types
of the methods. Then we go back and parse the fields for real. of the fields and then the start of the methods. Then we go back
This is ugly. */ and parse the fields for real. This is ugly. */
static int field_pass; static int field_pass;
/* Likewise we pass over methods twice. The first time we generate
#define HANDLE_END_FIELD() \ class decl information; the second time we generate actual method
if (out && field_pass) print_field_info (out, jcf, current_field_name, \ decls. */
current_field_signature, \ static int method_pass;
current_field_flags);
#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) #define HANDLE_CONSTANTVALUE(VALUEINDEX) current_field_value = (VALUEINDEX)
static int method_declared = 0; static int method_declared = 0;
static int method_access = 0; static int method_access = 0;
#define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \ static int method_printed = 0;
if (out) { decompiled = 0; \ #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
print_method_info (out, jcf, NAME, SIGNATURE, ACCESS_FLAGS); \ 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) \ #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
if (out && method_declared) decompile_method (out, jcf, CODE_LENGTH); if (out && method_declared) decompile_method (out, jcf, CODE_LENGTH);
static int decompiled = 0; static int decompiled = 0;
#define HANDLE_END_METHOD() \ #define HANDLE_END_METHOD() \
if (out) fputs (decompiled ? "\n" : ";\n", out); if (out && method_printed) fputs (decompiled ? "\n" : ";\n", out);
#include "jcf-reader.c" #include "jcf-reader.c"
...@@ -426,13 +448,24 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags), ...@@ -426,13 +448,24 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
fprintf (stream, "<not a UTF8 constant>"); fprintf (stream, "<not a UTF8 constant>");
str = JPOOL_UTF_DATA (jcf, name_index); str = JPOOL_UTF_DATA (jcf, name_index);
length = JPOOL_UTF_LENGTH (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, /* Ignore internally generated methods like <clinit> and
treat <init> as a constructor. */ $finit$. However, treat <init> as a constructor. */
if (! utf8_cmp (str, length, "<init>")) if (! utf8_cmp (str, length, "<init>"))
is_init = 1; 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; return;
} }
else else
...@@ -455,20 +488,22 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags), ...@@ -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. */ after it in the vtbl). So we give it a dummy name instead. */
if (! utf8_cmp (str, length, "delete")) if (! utf8_cmp (str, length, "delete"))
{ {
/* If the method is static, we can safely skip it. If we don't /* If the method is static or final, we can safely skip it. If
skip it then we'll have problems since the mangling will be we don't skip it then we'll have problems since the mangling
wrong. FIXME. */ will be wrong. FIXME. */
if ((flags & ACC_STATIC)) if (METHOD_IS_FINAL (jcf->access_flags, flags)
|| (flags & ACC_STATIC))
return; return;
override = "__dummy_delete"; override = "__dummy_delete";
} }
method_printed = 1;
generate_access (stream, flags); generate_access (stream, flags);
fputs (" ", out); fputs (" ", out);
if ((flags & ACC_STATIC)) if ((flags & ACC_STATIC))
fputs ("static ", out); 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. */ /* Don't print `virtual' if we have a constructor. */
if (! is_init) if (! is_init)
...@@ -795,39 +830,210 @@ super_class_name (derived_jcf, len) ...@@ -795,39 +830,210 @@ super_class_name (derived_jcf, len)
return supername; 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 /* This is used to represent part of a package or class name. */
declaration for each class which is the type of a return value, a struct namelet
field, or an argument. */ {
/* 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 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; FILE *out;
JCF *jcf; 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); int start;
if (kind == CONSTANT_Class) /* 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)) /* Skip all the standard `java.' classes. */
fputs (";\n", out); continue;
seen_one = 1;
} }
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) if (root.subnamelets)
fputs ("\n", out); {
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 static void
DEFUN(process_file, (jcf, out), DEFUN(process_file, (jcf, out),
JCF *jcf AND FILE *out) JCF *jcf AND FILE *out)
{ {
int code, i; int code, i;
uint32 field_start, method_end; uint32 field_start, method_end, method_start;
current_jcf = main_jcf = jcf; current_jcf = main_jcf = jcf;
...@@ -895,9 +1101,22 @@ DEFUN(process_file, (jcf, out), ...@@ -895,9 +1101,22 @@ DEFUN(process_file, (jcf, out),
fputs ("\n", 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) if (out)
{ {
print_class_decls (out, jcf); print_class_decls (out, jcf, jcf->this_class);
for (i = 0; i < prepend_count; ++i) for (i = 0; i < prepend_count; ++i)
fprintf (out, "%s\n", prepend_specs[i]); fprintf (out, "%s\n", prepend_specs[i]);
...@@ -923,18 +1142,9 @@ DEFUN(process_file, (jcf, out), ...@@ -923,18 +1142,9 @@ DEFUN(process_file, (jcf, out),
if (out) if (out)
fputs ("\n{\n", out); fputs ("\n{\n", out);
/* We make a single pass over the file, printing methods and fields /* Now go back for second pass over methods and fields. */
as we see them. We have to list the methods in the same order JCF_SEEK (jcf, method_start);
that they appear in the class file, so that the Java and C++ method_pass = 1;
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);
jcf_parse_methods (jcf); jcf_parse_methods (jcf);
method_end = JCF_TELL (jcf); method_end = JCF_TELL (jcf);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment