diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog index 07b89d6b89a..a8f7f208706 100644 --- a/gcc/java/ChangeLog +++ b/gcc/java/ChangeLog @@ -1,3 +1,12 @@ +2002-05-07 Tom Tromey + + Fix for PR java/1200: + * gjavah.c (throwable_p): New function. + (decode_signature_piece): Use it. A `WeakReference' isn't the + same as a `jweak'. + Include hashtab.h. + (gcjh_streq): New function. + 2002-05-07 Andreas Jaeger * parse.y (finish_for_loop): Fix if statement. diff --git a/gcc/java/gjavah.c b/gcc/java/gjavah.c index 4daaa2bcd3b..d152b372944 100644 --- a/gcc/java/gjavah.c +++ b/gcc/java/gjavah.c @@ -33,6 +33,7 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */ #include "javaop.h" #include "java-tree.h" #include "java-opcodes.h" +#include "hashtab.h" #include @@ -142,6 +143,8 @@ static char *get_field_name PARAMS ((JCF *, int, JCF_u2)); static void print_field_name PARAMS ((FILE *, JCF *, int, JCF_u2)); static const unsigned char *super_class_name PARAMS ((JCF *, int *)); static void print_include PARAMS ((FILE *, const unsigned char *, int)); +static int gcjh_streq PARAMS ((const void *p1, const void *p2)); +static int throwable_p PARAMS ((const unsigned char *signature)); static const unsigned char *decode_signature_piece PARAMS ((FILE *, const unsigned char *, const unsigned char *, int *)); static void print_class_decls PARAMS ((FILE *, JCF *, int)); @@ -1091,6 +1094,111 @@ decompile_method (out, jcf, code_len) } } +/* 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 (p1, p2) + const void *p1, *p2; +{ + return ! strcmp ((char *) p1, (char *) p2); +} + +/* Return 1 if the initial (L;) part of SIGNATURE names a + subclass of throwable, or 0 if not. */ +static int +throwable_p (signature) + const unsigned char *signature; +{ + 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) + { + PTR *slot; + const 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 = strdup ("java.lang.Throwable"); + slot = htab_find_slot (throw_hash, str, INSERT); + *slot = (PTR) str; + + str = strdup ("java.lang.Object"); + slot = htab_find_slot (non_throw_hash, str, INSERT); + *slot = (PTR) str; + + init_done = 1; + } + + for (length = 0; signature[length] != ';'; ++length) + ; + current = (unsigned char *) ALLOC (length); + for (i = 1; signature[i] != ';'; ++i) + current[i - 1] = signature[i] == '/' ? '.' : signature[i]; + current[i - 1] = '\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; + PTR *slot; + const char *classfile_name = find_class (current, strlen (current), + &jcf, 0); + + if (! classfile_name) + { + fprintf (stderr, "couldn't find class %s\n", current); + found_error = 1; + return 0; + } + if (jcf_parse_preamble (&jcf) != 0 + || jcf_parse_constant_pool (&jcf) != 0 + || verify_constant_pool (&jcf) > 0) + { + fprintf (stderr, "parse error while reading %s\n", classfile_name); + found_error = 1; + return 0; + } + jcf_parse_class (&jcf); + + result = throwable_p (super_class_name (&jcf, NULL)); + slot = htab_find_slot (result ? throw_hash : non_throw_hash, + current, INSERT); + *slot = current; + current = NULL; + + JCF_FINISH (&jcf); + } + + if (current) + free (current); + return result; +} + /* Print one piece of a signature. Returns pointer to next parseable character on success, NULL on error. */ static const unsigned char * @@ -1204,24 +1312,15 @@ decode_signature_piece (stream, signature, limit, need_space) case 'L': if (flag_jni) { - /* We know about certain types and special-case their - names. - FIXME: something like java.lang.Exception should be - printed as `jthrowable', because it is a subclass. This - means that gcjh must read the entire hierarchy and - comprehend it. */ + /* We know about certain types and special-case their names. */ if (! strncmp (signature, "Ljava/lang/String;", sizeof ("Ljava/lang/String;") -1)) ctype = "jstring"; else if (! strncmp (signature, "Ljava/lang/Class;", sizeof ("Ljava/lang/Class;") - 1)) ctype = "jclass"; - else if (! strncmp (signature, "Ljava/lang/Throwable;", - sizeof ("Ljava/lang/Throwable;") - 1)) + else if (throwable_p (signature)) ctype = "jthrowable"; - else if (! strncmp (signature, "Ljava/lang/ref/WeakReference;", - sizeof ("Ljava/lang/ref/WeakReference;") - 1)) - ctype = "jweak"; else ctype = "jobject";