This is the mail archive of the java-discuss@sources.redhat.com mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

New C++ ABI: patches.



This is a first trial at the new C++ ABI, in three patches. This let
me compile some examples, run the interpreter in some simple
cases. There are also some regressions.

There is a C++ front-end patch, for which I'm seeking approval (the
patch seems IMO pretty much ready.) Note that we need to allow
references type as the new ABI forces us to modify the way we
initialize Class objects for primitive types.

There's a large Java front-end, which implements the new mangling
scheme. Note that it wasn't really feasible to reuse the code written
by Alex Samuel, as it depends on DECL_LANG_SPECIFICs set by the C++
front-end. There are a lot of open issues, the most salient one is
what to do with unicode characters. The new C++ ABI doesn't make any
provision for such a case: what we do right now more or less mimics
what we used to do and we probably need to invent something: Jason
Merill proposed that we use UTF8 were possible (binutils would need to
be modified,) some limited target would use a simple hex encoding +
escape mechanism.

There's a run-time patch, which contains two important pieces. The
first one inserts two new virtual functions in Object.h, which tricks
the C++ compiler into giving us the two slots that the new ABI moves
at -1 and -2. The second one (thank you Tom for your suggestion) works
around a linking problem we found with the definition of _Jv_PrimClass
(for which the C++ compiler was defining a vtable which wasn't emitted
by anything else.) prims.cc:init_prim_class() does the job of
initializing Class objects for primitive types now bearing the
java::lang::Class type. The copy constructor builds what needs to
eventually go in _Jv_<type>Class, note that _Jv_FindArrayClass needs
to be called in the copy constructor, which forces us into a rather
ugly hack. Maybe java::lang::Class::initiazePrim() could be moved into
the copy constructor after all. This modification (I think) brings at
least one regression, this doesn't work anymore:

  class dotclass {
    static void foo (Object x) { System.out.println (x.toString()); }
    public static void main (String[] arg) { foo(int.class); }
  }

Can a runtime hacker look into this, as I'll be back online Monday
evening.

Note that the first hunk in the natClass.cc patch is necessary in
order to have java::lang::Class::isAssignableFrom's symbol defined. I
don't understand why it isn't the case with, say, 
java::lang::Class::isInstance.

Let me know what you think and how it works for you. 

./A

C++ front end patch:

2001-01-07  Alexandre Petit-Bianco  <apbianco@cygnus.com>

	* decl2.c (acceptable_java_type): Allow references too. 
	* init.c (build_java_class_ref): New local `field.' Search
	`class$' and have it mangled with `mangle_decl.'
	* mangle.c (write_java_integer_type_codes): New function.
	(write_builtin_type): Detect and mangle Java integer and real
	types.

Index: decl2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl2.c,v
retrieving revision 1.416
diff -u -p -r1.416 decl2.c
--- decl2.c	2000/12/07 07:56:43	1.416
+++ decl2.c	2001/01/07 15:31:04
@@ -1337,7 +1337,7 @@ acceptable_java_type (type)
 {
   if (TREE_CODE (type) == VOID_TYPE || TYPE_FOR_JAVA (type))
     return 1;
-  if (TREE_CODE (type) == POINTER_TYPE)
+  if (TREE_CODE (type) == POINTER_TYPE || TREE_CODE (type) == REFERENCE_TYPE)
     {
       type = TREE_TYPE (type);
       if (TREE_CODE (type) == RECORD_TYPE)
Index: init.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/init.c,v
retrieving revision 1.223
diff -u -p -r1.223 init.c
--- init.c	2000/12/15 16:36:00	1.223
+++ init.c	2001/01/07 15:31:37
@@ -2166,7 +2166,7 @@ tree
 build_java_class_ref (type)
      tree type;
 {
-  tree name, class_decl;
+  tree name, class_decl, field;
   static tree CL_suffix = NULL_TREE;
   if (CL_suffix == NULL_TREE)
     CL_suffix = get_identifier("class$");
@@ -2177,7 +2177,17 @@ build_java_class_ref (type)
 	fatal("call to Java constructor, while `jclass' undefined");
       jclass_node = TREE_TYPE (jclass_node);
     }
-  name = build_static_name (type, CL_suffix);
+
+  /* Mangle the class$ field. */
+  for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+    if (DECL_NAME (field) == CL_suffix)
+      {
+	name = mangle_decl (field);
+	break;
+      }
+  if (!field)
+    fatal ("Can't find class$");
+
   class_decl = IDENTIFIER_GLOBAL_VALUE (name);
   if (class_decl == NULL_TREE)
     {
Index: mangle.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/mangle.c,v
retrieving revision 1.23
diff -u -p -r1.23 mangle.c
--- mangle.c	2000/12/04 17:00:03	1.23
+++ mangle.c	2001/01/07 15:31:58
@@ -189,6 +189,10 @@ static inline void start_mangling PARAMS
 static inline const char *finish_mangling PARAMS ((void));
 static tree mangle_special_for_type PARAMS ((tree, const char *));
 
+/* Foreign language functions. */
+
+static void write_java_integer_type_codes PARAMS ((tree));
+
 /* Append a single character to the end of the mangled
    representation.  */
 #define write_char(CHAR)                                              \
@@ -1446,6 +1450,8 @@ write_builtin_type (type)
 	 integer_type_nodes.  */
       if (type == wchar_type_node)
 	write_char ('w');
+      if (TYPE_FOR_JAVA (type))
+	write_java_integer_type_codes (type);
       else
 	{
 	  size_t itk;
@@ -1473,9 +1479,11 @@ write_builtin_type (type)
       break;
 
     case REAL_TYPE:
-      if (type == float_type_node)
+      if (type == float_type_node
+	  || type == java_float_type_node)
 	write_char ('f');
-      else if (type == double_type_node)
+      else if (type == double_type_node
+	       || type == java_double_type_node)
 	write_char ('d');
       else if (type == long_double_type_node)
 	write_char ('e');
@@ -2280,3 +2288,30 @@ mangle_guard_variable (variable)
   write_name (variable, /*ignore_local_scope=*/0);
   return get_identifier (finish_mangling ());
 }
+
+
+
+/* Foreign language type mangling section.  */
+
+/* How to write the type codes for the integer Java type.  */
+
+static void
+write_java_integer_type_codes (type)
+     tree type;
+{
+  if (type == java_int_type_node)
+    write_char ('i');
+  else if (type == java_short_type_node)
+    write_char ('s');
+  else if (type == java_byte_type_node)
+    write_char ('c');
+  else if (type == java_char_type_node)
+    write_char ('w');
+  else if (type == java_long_type_node)
+    write_char ('x');
+  else if (type == java_boolean_type_node)
+    write_char ('b');
+  else
+    my_friendly_abort (20001207);
+}
+

Java runtime patch:

2001-01-07  Alexandre Petit-Bianco  <apbianco@cygnus.com>

	* prims.cc (class _Jv_PrimClass): Removed.
	(init_prim_class): New function.
	(DECLARE_PRIM_TYPE): Rewritten. `java::lang::Class' replaces
	`_Jv_PrimClass' in primitive type declarations. Assign to the
	value returned by `init_prim_class.'
	* gcj/array.h: `java::lang::Class' replaces `_Jv_PrimClass' in
	primitive type declarations.
	(JvPrimClass): Cast to `jclass' removed.
	* java/lang/Class.h (Class): New constructor.
	(Class): New copy constructor.
	(initializePrim): New prototype.
	(_Jv_PrimClass): Field removed.
	* java/lang/Object.h (class java::lang::Object): New virtuals
	nacd_1 and nacd_2 (for compatibility with the new C++ ABI.)
	* java/lang/natClass.cc (initializePrim): New function.

Index: prims.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/prims.cc,v
retrieving revision 1.42
diff -u -p -r1.42 prims.cc
--- prims.cc	2000/11/27 04:05:23	1.42
+++ prims.cc	2001/01/07 15:36:28
@@ -516,52 +516,22 @@ _Jv_NewMultiArray (jclass array_type, ji
 
 
 
-class _Jv_PrimClass : public java::lang::Class
+// Initialize Class object for primitive types. The `return' statement
+// does the actuall job.
+static java::lang::Class
+init_prim_class (jobject cname, jbyte sig, jint len, jobject array_vtable)
 {
-public:
-  // FIXME: calling convention is weird.  If we use the natural types
-  // then the compiler will complain because they aren't Java types.
-  _Jv_PrimClass (jobject cname, jbyte sig, jint len, jobject array_vtable)
-    {
-      using namespace java::lang::reflect;
+  static java::lang::Class iclass;
 
-      // We must initialize every field of the class.  We do this in
-      // the same order they are declared in Class.h.
-      next = NULL;
-      name = _Jv_makeUtf8Const ((char *) cname, -1);
-      accflags = Modifier::PUBLIC | Modifier::FINAL;
-      superclass = NULL;
-      constants.size = 0;
-      constants.tags = NULL;
-      constants.data = NULL;
-      methods = NULL;
-      method_count = sig;
-      vtable_method_count = 0;
-      fields = NULL;
-      size_in_bytes = len;
-      field_count = 0;
-      static_field_count = 0;
-      vtable = JV_PRIMITIVE_VTABLE;
-      interfaces = NULL;
-      loader = NULL;
-      interface_count = 0;
-      state = JV_STATE_DONE;
-      thread = NULL;
+  iclass.initializePrim (cname, sig, len, array_vtable);
+  return iclass;
+}
 
-      // Note that we have to set `methods' to NULL.
-      if (sig != 'V')
-	_Jv_FindArrayClass (this, NULL, (_Jv_VTable *) array_vtable);
-    }
-};
-
-// We use this to define both primitive classes and the vtables for
-// arrays of primitive classes.  The latter are given names so that we
-// can refer to them from the compiler, allowing us to construct
-// arrays of primitives statically.
-#define DECLARE_PRIM_TYPE(NAME, SIG, LEN) \
-  _Jv_ArrayVTable _Jv_##NAME##VTable; \
-  _Jv_PrimClass _Jv_##NAME##Class((jobject) #NAME, (jbyte) SIG, (jint) LEN, \
-                                  (jobject) &_Jv_##NAME##VTable)
+#define DECLARE_PRIM_TYPE(NAME, SIG, LEN)				\
+  _Jv_ArrayVTable _Jv_##NAME##VTable;					\
+  java::lang::Class _Jv_##NAME##Class = 				\
+    init_prim_class ((jobject) #NAME, (jbyte) SIG,			\
+		     (jint) LEN, (jobject) &_Jv_##NAME##VTable);
 
 DECLARE_PRIM_TYPE(byte, 'B', 1);
 DECLARE_PRIM_TYPE(short, 'S', 2);
Index: gcj/array.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gcj/array.h,v
retrieving revision 1.11
diff -u -p -r1.11 array.h
--- array.h	2000/11/27 04:05:23	1.11
+++ array.h	2001/01/07 15:36:28
@@ -60,10 +60,10 @@ typedef JArray<jfloat> *jfloatArray;
 typedef JArray<jdouble> *jdoubleArray;
 typedef JArray<jstring> *jstringArray;
 
-extern class _Jv_PrimClass _Jv_byteClass, _Jv_shortClass, _Jv_intClass,
+extern java::lang::Class _Jv_byteClass, _Jv_shortClass, _Jv_intClass,
   _Jv_longClass, _Jv_booleanClass, _Jv_charClass, _Jv_floatClass,
   _Jv_doubleClass, _Jv_voidClass;
-#define JvPrimClass(TYPE) ((jclass) & _Jv_##TYPE##Class)
+#define JvPrimClass(TYPE) (& _Jv_##TYPE##Class)
 
 extern "C" jobjectArray _Jv_NewObjectArray(jsize length, jclass, jobject init);
 extern "C" jobject _Jv_NewPrimArray (jclass eltype, jint count);
Index: java/lang/Class.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/Class.h,v
retrieving revision 1.27
diff -u -p -r1.27 Class.h
--- Class.h	2000/11/26 03:58:55	1.27
+++ Class.h	2001/01/07 15:36:32
@@ -191,6 +191,25 @@ public:
   // finalization
   void finalize ();
 
+  // For the initialization of primitive types: some constructors as
+  // required by prims.cc:init_prim_class(), and the prototype of
+  // method to perform a lightweight initialization of a Class object.
+  Class (void) {}
+  Class (const Class& x) : Object () {
+    _Jv_VTable *avtable = x.vtable;
+
+    name = x.name;
+    accflags = x.accflags;
+    method_count = x.method_count;
+    size_in_bytes = x.size_in_bytes;
+    vtable = x.vtable;
+    vtable = JV_PRIMITIVE_VTABLE;
+    state = x.state;
+    if (method_count != 'V')
+      _Jv_FindArrayClass (this, 0, avtable);
+  }
+  void initializePrim (jobject cname, jbyte sig, jint len, jobject avtable);
+
   static java::lang::Class class$;
 
 private:   
@@ -236,8 +255,6 @@ private:   
   friend jmethodID _Jv_FromReflectedConstructor (java::lang::reflect::Constructor *);
   friend jint JvNumMethods (jclass);
   friend jmethodID JvGetFirstMethod (jclass);
-
-  friend class _Jv_PrimClass;
 
   // Friends classes and functions to implement the ClassLoader
   friend class java::lang::ClassLoader;
Index: java/lang/Object.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/Object.h,v
retrieving revision 1.6
diff -u -p -r1.6 Object.h
--- Object.h	2000/10/06 01:49:31	1.6
+++ Object.h	2001/01/07 15:36:37
@@ -33,6 +33,9 @@ protected:
 class java::lang::Object : public _JvObjectPrefix
 {
 public:
+  // New ABI Compatibility Dummy, #1 and 2.
+  virtual void nacd_1 (void);
+  virtual void nacd_2 (void);
   // Order must match order in Object.java.
   jclass getClass (void);
   virtual jint hashCode (void);
Index: java/lang/natClass.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/natClass.cc,v
retrieving revision 1.30
diff -u -p -r1.30 natClass.cc
--- natClass.cc	2000/11/26 03:58:55	1.30
+++ natClass.cc	2001/01/07 15:36:50
@@ -615,7 +615,7 @@ java::lang::Class::getMethods (void)
   return result;
 }
 
-inline jboolean
+jboolean
 java::lang::Class::isAssignableFrom (jclass klass)
 {
   // Arguments may not have been initialized, given ".class" syntax.
@@ -1398,3 +1398,38 @@ java::lang::Class::getPrivateMethod (jst
   JvThrow (new java::lang::NoSuchMethodException);
 }
 
+// Perform a lightweight initialization of a Class object, for the
+// purpose of creating the Class object of primitive types.
+
+void
+java::lang::Class::initializePrim (jobject cname, jbyte sig, jint len, jobject avtable)
+{
+  using namespace java::lang::reflect;
+
+  // We must initialize every field of the class.  We do this in
+  // the same order they are declared in Class.h.
+  next = NULL;
+  name = _Jv_makeUtf8Const ((char *) cname, -1);
+  accflags = Modifier::PUBLIC | Modifier::FINAL;
+  superclass = NULL;
+  constants.size = 0;
+  constants.tags = NULL;
+  constants.data = NULL;
+  methods = NULL;
+  method_count = sig;
+  vtable_method_count = 0;
+  fields = NULL;
+  size_in_bytes = len;
+  field_count = 0;
+  static_field_count = 0;
+ 
+  // We temporarily store `avtable' in the `vtable' field, so that the
+  // copy constructor can correctly invoke _Jv_FindArrayClass.
+  vtable = (_Jv_VTable *) avtable;
+
+  interfaces = NULL;
+  loader = NULL;
+  interface_count = 0;
+  state = JV_STATE_DONE;
+  thread = NULL;
+}

Java frontend patch:

2001-01-07  Alexandre Petit-Bianco  <apbianco@cygnus.com>

	* Make-lang.in (JVGENMAIN_OBS): Removed java/mangle.o.
	* class.c (mangle_class_field): Function removed.
	(append_gpp_mangled_type, mangle_static_field, mangle_field): Likewise.
	(utf8_cmp, cxx_keyword_p): Moved to lex.c.
	(build_class_ref): Call `java_mangle_class_field' instead of
	`mangle_class_field.'
	(build_dtable_decl): Rewritten to call `java_mangle_vtable.'
	(layout_class): Call `java_mangle_decl' instead of 
	`mangle_static_field.'
	(cxx_keywords): Initialized static array moved to `lex.c.'
	(layout_class_method): Changed leading comment. Simplified to
	call `java_mangle_decl.' Local `ptr' moved in for loop body.
	* decl.c (lang_mark_tree): Mark field `package_list.'
	* java-tree.h (TYPE_PACKAGE_LIST): New macro.
	(struct lang_type): New field `package_list.'
	(unicode_mangling_length): Prototype removed.
	(append_gpp_mangled_name, append_gpp_mangled_classtype,
	emit_unicode_mangled_name): Likewise.
	(cxx_keyword_p): New prototype.
	(java_mangle_decl, java_mangle_class_field,
	java_mangle_class_field_from_string, java_mangle_vtable): Likewise.
	* jcf-parse.c (jcf_parse_source): Constify `file' argument to
	`build_expr_wfl.'
	* jvgenmain.c (main_method_prefix): Global variable removed.
	(main_method_suffix): Likewise.
	(do_mangle_classname): New function.
	(main): Call it. Format changed to accomodate new mangling scheme.
	* lex.c: (utf8_cmp): Conditionally prototyped.
	(cxx_keywords): Moved from class.c, conditionally defined.
	(utf8_cmp, cxx_keyword_p): Likewise.
	* mangle.c (obstack.h, ggc.h): Included.
	(mangle_field_decl): New function.
	(mangle_method_decl, mangle_type, mangle_pointer_type,
	mangle_array_type, mangle_record_type,
	find_compression_pointer_match, find_compression_array_match,
	find_compression_record_match,
	find_compression_array_template_match, set_type_package_list,
	entry_match_pointer_p, emit_compression_string, init_mangling,
	finish_mangling, compression_table_add, mangle_member_name): Likewise.
	(mangle_obstack): New global.
	(MANGLE_RAW_STRING): New macro.
	(unicode_mangling_length): Turned static.
	(append_unicode_mangled_name): Renamed from
	`emit_unicode_mangled_name.'  Turned static. `mangle_obstack'
	replaces `obstack', removed from the parameter list.
	(append_gpp_mangled_name): Turned static. `mangle_obstack'
	replaces parameter `obstack', removed from the parameter list. Call 
	`append_unicode_mangled_name' instead of `emit_unicode_mangled_name.
	(append_gpp_mangled_classtype): Removed.
	(compression_table, compression_next): New static variables.
	* parse.y (temporary_obstack): Extern declaration removed.

Index: Make-lang.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/Make-lang.in,v
retrieving revision 1.46
diff -u -p -r1.46 Make-lang.in
--- Make-lang.in	2000/12/13 22:47:13	1.46
+++ Make-lang.in	2001/01/07 15:22:48
@@ -111,7 +111,7 @@ JVSCAN_OBJS = java/parse-scan.o java/jv-
 JCFDUMP_OBJS = java/jcf-dump.o java/jcf-io.o java/jcf-depend.o java/jcf-path.o \
 		java/zextract.o errors.o version.o mkdeps.o
 
-JVGENMAIN_OBJS = java/jvgenmain.o java/mangle.o
+JVGENMAIN_OBJS = java/jvgenmain.o
 
 # Use loose warnings for this front end.
 java-warn =
Index: class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/class.c,v
retrieving revision 1.81
diff -u -p -r1.81 class.c
--- class.c	2000/12/18 21:15:52	1.81
+++ class.c	2001/01/07 15:23:12
@@ -37,25 +37,18 @@ The Free Software Foundation is independ
 #include "parse.h"
 #include "ggc.h"
 
-static tree mangle_class_field PARAMS ((tree class));
 static tree make_method_value PARAMS ((tree));
 static tree build_java_method_type PARAMS ((tree, tree, int));
 static int32 hashUtf8String PARAMS ((const char *, int));
 static tree make_field_value PARAMS ((tree));
 static tree get_dispatch_vector PARAMS ((tree));
 static tree get_dispatch_table PARAMS ((tree, tree));
-static void append_gpp_mangled_type PARAMS ((struct obstack *, tree));
-static tree mangle_static_field PARAMS ((tree));
 static void add_interface_do PARAMS ((tree, tree, int));
 static tree maybe_layout_super_class PARAMS ((tree, tree));
 static int assume_compiled PARAMS ((const char *));
 static struct hash_entry *init_test_hash_newfunc PARAMS ((struct hash_entry *,
 							  struct hash_table *,
 							  hash_table_key));
-static int utf8_cmp PARAMS ((const unsigned char *, int, const char *));
-static int cxx_keyword_p PARAMS ((const char *, int));
-static tree mangle_field PARAMS ((tree, tree));
-
 static rtx registerClass_libfunc;
 
 extern struct obstack permanent_obstack;
@@ -890,7 +883,8 @@ build_class_ref (type)
 	      TREE_PUBLIC (decl) = 1;
 	      DECL_IGNORED_P (decl) = 1;
 	      DECL_ARTIFICIAL (decl) = 1;
-	      DECL_ASSEMBLER_NAME (decl) = mangle_class_field (type);
+	      DECL_ASSEMBLER_NAME (decl) = 
+		java_mangle_class_field (&temporary_obstack, type);
 	      make_decl_rtl (decl, NULL, 1);
 	      pushdecl_top_level (decl);
 	      if (is_compiled == 1)
@@ -1544,147 +1538,13 @@ is_compiled_class (class)
   return 0;
 }
 
-/* Append the mangled name of TYPE onto OBSTACK. */
-
-static void
-append_gpp_mangled_type (obstack, type)
-     struct obstack *obstack;
-     tree type;
-{
-  switch (TREE_CODE (type))
-    {
-      char code;
-    case BOOLEAN_TYPE: code = 'b';  goto primitive;
-    case CHAR_TYPE:    code = 'w';  goto primitive;
-    case VOID_TYPE:    code = 'v';  goto primitive;
-    case INTEGER_TYPE:
-      /* Get the original type instead of the arguments promoted type.
-	 Avoid symbol name clashes. Should call a function to do that.
-	 FIXME.  */
-      if (type == promoted_short_type_node)
-	type = short_type_node;
-      if (type == promoted_byte_type_node)
-        type = byte_type_node;
-      switch (TYPE_PRECISION (type))
-	{
-	case  8:       code = 'c';  goto primitive;
-	case 16:       code = 's';  goto primitive;
-	case 32:       code = 'i';  goto primitive;
-	case 64:       code = 'x';  goto primitive;
-	default:  goto bad_type;
-	}
-    primitive:
-      obstack_1grow (obstack, code);
-      break;
-    case REAL_TYPE:
-      switch (TYPE_PRECISION (type))
-	{
-	case 32:       code = 'f';  goto primitive;
-	case 64:       code = 'd';  goto primitive;
-	default:  goto bad_type;
-	}
-    case POINTER_TYPE:
-      type = TREE_TYPE (type);
-      obstack_1grow (obstack, 'P');
-    case RECORD_TYPE:
-      if (TYPE_ARRAY_P (type))
-	{
-	  obstack_grow (obstack, "t6JArray1Z", sizeof("t6JArray1Z")-1);
-	  append_gpp_mangled_type (obstack, TYPE_ARRAY_ELEMENT (type));
-	}
-      else
-	{
-	  const char *class_name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
-	  append_gpp_mangled_classtype (obstack, class_name);
-	}
-      break;
-    bad_type:
-    default:
-      fatal ("internal error - trying to mangle unknown type");
-    }
-}
-
-/* Build the mangled name of a field, given the class name and the
-   field name.  */
-
-static tree
-mangle_field (class, name)
-     tree class, name;
-{
-  int encoded_len;
-#if ! defined (NO_DOLLAR_IN_LABEL) || ! defined (NO_DOT_IN_LABEL)
-  obstack_1grow (&temporary_obstack, '_');
-#else
-  obstack_grow (&temporary_obstack, "__static_", 9);
-#endif
-  append_gpp_mangled_type (&temporary_obstack, class);
-  encoded_len = unicode_mangling_length (IDENTIFIER_POINTER (name),
-					 IDENTIFIER_LENGTH (name));
-  if (encoded_len > 0)
-    {
-      obstack_1grow (&temporary_obstack, 'U');
-    }
-#ifndef NO_DOLLAR_IN_LABEL
-  obstack_1grow (&temporary_obstack, '$');
-#else /* NO_DOLLAR_IN_LABEL */
-#ifndef NO_DOT_IN_LABEL
-  obstack_1grow (&temporary_obstack, '.');
-#else /* NO_DOT_IN_LABEL */
-  obstack_1grow (&temporary_obstack, '_');
-#endif  /* NO_DOT_IN_LABEL */
-#endif  /* NO_DOLLAR_IN_LABEL */
-  if (encoded_len > 0)
-    {
-      emit_unicode_mangled_name (&temporary_obstack,
-				 IDENTIFIER_POINTER (name), 
-				 IDENTIFIER_LENGTH (name));
-    }
-  else
-    {
-      obstack_grow (&temporary_obstack,
-		    IDENTIFIER_POINTER (name),
-		    IDENTIFIER_LENGTH (name));
-    }
-
-  /* Mangle C++ keywords by appending a `$'.  */
-  /* FIXME: NO_DOLLAR_IN_LABEL */
-  if (cxx_keyword_p (IDENTIFIER_POINTER (name), IDENTIFIER_LENGTH (name)))
-    obstack_grow (&temporary_obstack, "$", 1);
-
-  obstack_1grow (&temporary_obstack, '\0');
-  name = get_identifier (obstack_base (&temporary_obstack));
-  obstack_free (&temporary_obstack, obstack_base (&temporary_obstack));
-  return name;
-}
-
-/* Build the mangled name of the `class' field.  */
-
-static tree
-mangle_class_field (class)
-     tree class;
-{
-  /* We know that we can use `class$' to mangle the class object,
-     because `class' is a reserved word in Java and thus can't appear
-     as a field or method name.  */
-  return mangle_field (class, get_identifier ("class$"));
-}
-
-/* Build the mangled (assembly-level) name of the static field FIELD. */
-
-static tree
-mangle_static_field (field)
-     tree field;
-{
-  return mangle_field (DECL_CONTEXT (field), DECL_NAME (field));
-}
-
 /* Build a VAR_DECL for the dispatch table (vtable) for class TYPE. */
 
 tree
 build_dtable_decl (type)
      tree type;
 {
-  tree name, dtype;
+  tree dtype;
 
   /* We need to build a new dtable type so that its size is uniquely
      computed when we're dealing with the class for real and not just
@@ -1705,12 +1565,8 @@ build_dtable_decl (type)
   else
     dtype = dtable_type;
 
-  obstack_grow (&temporary_obstack, "__vt_", 5);
-  append_gpp_mangled_type (&temporary_obstack, type);
-  obstack_1grow (&temporary_obstack, '\0');
-  name = get_identifier (obstack_base (&temporary_obstack));
-  obstack_free (&temporary_obstack, obstack_base (&temporary_obstack));
-  return build_decl (VAR_DECL, name, dtype);
+  return build_decl (VAR_DECL, 
+		     java_mangle_vtable (&temporary_obstack, type), dtype);
 }
 
 /* Pre-pend the TYPE_FIELDS of THIS_CLASS with a dummy FIELD_DECL for the
@@ -1835,7 +1691,8 @@ layout_class (this_class)
       if (FIELD_STATIC (field))
 	{
 	  /* Set DECL_ASSEMBLER_NAME to something suitably mangled. */
-	  DECL_ASSEMBLER_NAME (field) = mangle_static_field (field);
+	  DECL_ASSEMBLER_NAME (field) = 
+	    java_mangle_decl (&temporary_obstack, field);
 	}
     }
 
@@ -1915,218 +1772,38 @@ layout_class_methods (this_class)
 #endif
 }
 
-/* A sorted list of all C++ keywords.  */
-
-static const char *cxx_keywords[] =
-{
-  "asm",
-  "auto",
-  "bool",
-  "const_cast",
-  "delete",
-  "dynamic_cast",
-  "enum",
-  "explicit",
-  "extern",
-  "friend",
-  "inline",
-  "mutable",
-  "namespace",
-  "overload",
-  "register",
-  "reinterpret_cast",
-  "signed",
-  "sizeof",
-  "static_cast",
-  "struct",
-  "template",
-  "typedef",
-  "typeid",
-  "typename",
-  "typenameopt",
-  "union",
-  "unsigned",
-  "using",
-  "virtual",
-  "volatile",
-  "wchar_t"
-};
-
 /* 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 (str, length, name)
-     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;
-}
-
-/* Return true if NAME is a C++ keyword.  */
-
-static int
-cxx_keyword_p (name, length)
-     const char *name;
-     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 (name, min_length, cxx_keywords[mid]);
-
-      if (r == 0)
-	{
-	  int i;
-	  /* We've found a match if all the remaining characters are
-	     `$'.  */
-	  for (i = min_length; i < length && name[i] == '$'; ++i)
-	    ;
-	  if (i == length)
-	    return 1;
-	  r = 1;
-	}
-
-      if (r < 0)
-	last = mid;
-      else
-	first = mid;
-    }
-  return 0;
-}
-
 /* Lay METHOD_DECL out, returning a possibly new value of
-   DTABLE_COUNT.  */
+   DTABLE_COUNT. Also mangle the method's name. */
 
 tree
 layout_class_method (this_class, super_class, method_decl, dtable_count)
      tree this_class, super_class, method_decl, dtable_count;
 {
-  const char *ptr;
-  char *asm_name;
-  tree arg, arglist, t;
-  int method_name_needs_escapes = 0;
   tree method_name = DECL_NAME (method_decl);
   int method_name_is_wfl = 
     (TREE_CODE (method_name) == EXPR_WITH_FILE_LOCATION);
   if (method_name_is_wfl)
     method_name = java_get_real_method_name (method_decl);
 
-  if (!ID_INIT_P (method_name) && !ID_FINIT_P (method_name))
-    {
-      int encoded_len
-	= unicode_mangling_length (IDENTIFIER_POINTER (method_name), 
-				   IDENTIFIER_LENGTH (method_name));
-      if (encoded_len > 0)
-	{
-	  method_name_needs_escapes = 1;
-	  emit_unicode_mangled_name (&temporary_obstack,
-				     IDENTIFIER_POINTER (method_name), 
-				     IDENTIFIER_LENGTH (method_name));
-	}
-      else
-	{
-	  obstack_grow (&temporary_obstack,
-			IDENTIFIER_POINTER (method_name),
-			IDENTIFIER_LENGTH (method_name));
-	}
-
-      /* Mangle C++ keywords by appending a `$'.  */
-      /* FIXME: NO_DOLLAR_IN_LABEL */
-      if (cxx_keyword_p (IDENTIFIER_POINTER (method_name),
-			 IDENTIFIER_LENGTH (method_name)))
-	obstack_grow (&temporary_obstack, "$", 1);
-    }
-
-  obstack_grow (&temporary_obstack, "__", 2);
-  if (ID_FINIT_P (method_name))
-    obstack_grow (&temporary_obstack, "finit", 5);
-  append_gpp_mangled_type (&temporary_obstack, this_class);
   TREE_PUBLIC (method_decl) = 1;
 
-  t = TREE_TYPE (method_decl);
-  arglist = TYPE_ARG_TYPES (t);
-  if (TREE_CODE (t) == METHOD_TYPE)
-    arglist = TREE_CHAIN (arglist);
-  for (arg = arglist; arg != end_params_node;  )
-    {
-      tree a = arglist;
-      tree argtype = TREE_VALUE (arg);
-      int tindex = 1;
-      if (TREE_CODE (argtype) == POINTER_TYPE)
-	{
-	  /* This is O(N**2).  Do we care?  Cfr gcc/cp/method.c. */
-	  while (a != arg && argtype != TREE_VALUE (a))
-	    a = TREE_CHAIN (a), tindex++;
-	}
-      else
-	a = arg;
-      if (a != arg)
-	{
-	  char buf[12];
-	  int nrepeats = 0;
-	  do
-	    {
-	      arg = TREE_CHAIN (arg); nrepeats++;
-	    }
-	  while (arg != end_params_node && argtype == TREE_VALUE (arg));
-	  if (nrepeats > 1)
-	    {
-	      obstack_1grow (&temporary_obstack, 'N');
-	      sprintf (buf, "%d", nrepeats);
-	      obstack_grow (&temporary_obstack, buf, strlen (buf));
-	      if (nrepeats > 9)
-		obstack_1grow (&temporary_obstack, '_');
-	    }
-	  else
-	    obstack_1grow (&temporary_obstack, 'T');
-	  sprintf (buf, "%d", tindex);
-	  obstack_grow (&temporary_obstack, buf, strlen (buf));
-	  if (tindex > 9)
-	    obstack_1grow (&temporary_obstack, '_');
-	}
-      else
-	{
-	  append_gpp_mangled_type (&temporary_obstack, argtype);
-	  arg = TREE_CHAIN (arg);
-	}
-    }
-  if (method_name_needs_escapes)
-    obstack_1grow (&temporary_obstack, 'U');
-
-  obstack_1grow (&temporary_obstack, '\0');
-  asm_name = obstack_finish (&temporary_obstack);
-  DECL_ASSEMBLER_NAME (method_decl) = get_identifier (asm_name);
+  /* This is a good occasion to mangle the method's name */
+  DECL_ASSEMBLER_NAME (method_decl) = 
+    java_mangle_decl (&temporary_obstack, method_decl);
   /* We don't generate a RTL for the method if it's abstract, or if
      it's an interface method that isn't clinit. */
   if (! METHOD_ABSTRACT (method_decl) 
       || (CLASS_INTERFACE (TYPE_NAME (this_class)) 
 	  && (DECL_CLINIT_P (method_decl))))
     make_function_rtl (method_decl);
-  obstack_free (&temporary_obstack, asm_name);
 
   if (ID_INIT_P (method_name))
     {
       const char *p = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (this_class)));
+      const char *ptr;
       for (ptr = p; *ptr; )
 	{
 	  if (*ptr++ == '.')
@@ -2152,16 +1829,6 @@ layout_class_method (this_class, super_c
 	      && !CLASS_FROM_SOURCE_P (this_class))
 	    error_with_decl (method_decl,
 			     "non-static method '%s' overrides static method");
-#if 0
-	  else if (TREE_TYPE (TREE_TYPE (method_decl))
-		   != TREE_TYPE (TREE_TYPE (super_method)))
-	    {
-	      error_with_decl (method_decl,
-			       "Method `%s' redefined with different return type");  
-	      error_with_decl (super_method,
-			       "Overridden decl is here");
-	    }
-#endif
 	}
       else if (! METHOD_FINAL (method_decl)
 	       && ! METHOD_PRIVATE (method_decl)
Index: decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/decl.c,v
retrieving revision 1.79
diff -u -p -r1.79 decl.c
--- decl.c	2000/12/06 18:55:42	1.79
+++ decl.c	2001/01/07 15:23:37
@@ -1938,6 +1938,7 @@ lang_mark_tree (t)
 	  ggc_mark_tree (lt->clinit_stmt_list);
 	  ggc_mark_tree (lt->ii_block);
 	  ggc_mark_tree (lt->dot_class);
+	  ggc_mark_tree (lt->package_list);
 	}
     }
 }
Index: java-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/java-tree.h,v
retrieving revision 1.90
diff -u -p -r1.90 java-tree.h
--- java-tree.h	2000/12/06 18:55:42	1.90
+++ java-tree.h	2001/01/07 15:23:57
@@ -892,6 +892,7 @@ struct lang_decl_var
 /* The decl of the synthetic method `class$' used to handle `.class'
    for non primitive types when compiling to bytecode. */
 #define TYPE_DOT_CLASS(T)        (TYPE_LANG_SPECIFIC(T)->dot_class)
+#define TYPE_PACKAGE_LIST(T)     (TYPE_LANG_SPECIFIC(T)->package_list)
 #define TYPE_PRIVATE_INNER_CLASS(T) (TYPE_LANG_SPECIFIC(T)->pic)
 #define TYPE_PROTECTED_INNER_CLASS(T) (TYPE_LANG_SPECIFIC(T)->poic)
 #define TYPE_HAS_FINAL_VARIABLE(T) (TYPE_LANG_SPECIFIC(T)->afv)
@@ -909,6 +910,7 @@ struct lang_type
 				   needs to be invoked and generated when
 				   compiling to bytecode to implement
 				   <non_primitive_type>.class */
+  tree package_list;		/* List of package names, progressive */
   unsigned pic:1;		/* Private Inner Class. */
   unsigned poic:1;		/* Protected Inner Class. */
   unsigned afv:1;		/* Has final variables */
@@ -1043,7 +1045,6 @@ extern void check_for_initialization PAR
 
 extern tree pushdecl_top_level PARAMS ((tree));
 extern int alloc_class_constant PARAMS ((tree));
-extern int unicode_mangling_length PARAMS ((const char *, int));
 extern void init_expr_processing PARAMS ((void));
 extern void push_super_field PARAMS ((tree, tree));
 extern void init_class_processing PARAMS ((void));
@@ -1060,9 +1061,6 @@ extern int merge_type_state PARAMS ((tre
 extern void push_type PARAMS ((tree));
 extern void load_type_state PARAMS ((tree));
 extern void add_interface PARAMS ((tree, tree));
-extern void append_gpp_mangled_name PARAMS ((struct obstack *, const char *, int));
-extern void append_gpp_mangled_classtype PARAMS ((struct obstack *, const char *));
-extern void emit_unicode_mangled_name PARAMS ((struct obstack *, const char *, int));
 extern tree force_evaluation_order PARAMS ((tree));
 extern int verify_constant_pool PARAMS ((struct JCF *));
 extern void start_java_method PARAMS ((tree));
@@ -1111,6 +1109,12 @@ extern boolean java_hash_compare_tree_no
 						    hash_table_key));
 extern void java_check_methods PARAMS ((tree));
 extern void init_jcf_parse PARAMS((void));
+extern int cxx_keyword_p PARAMS ((const char *, int));
+extern tree java_mangle_decl PARAMS ((struct obstack *, tree));
+extern tree java_mangle_class_field PARAMS ((struct obstack *, tree));
+extern tree java_mangle_class_field_from_string PARAMS ((struct obstack *, char *));
+
+extern tree java_mangle_vtable PARAMS ((struct obstack *, tree));
 
 /* We use ARGS_SIZE_RTX to indicate that gcc/expr.h has been included
    to declare `enum expand_modifier'. */
Index: jcf-parse.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/jcf-parse.c,v
retrieving revision 1.67
diff -u -p -r1.67 jcf-parse.c
--- jcf-parse.c	2000/12/16 01:51:51	1.67
+++ jcf-parse.c	2001/01/07 15:24:13
@@ -569,7 +569,7 @@ jcf_parse_source ()
   java_push_parser_context ();
   BUILD_FILENAME_IDENTIFIER_NODE (file, current_jcf->filename);
   if (wfl_operator == NULL_TREE)
-    wfl_operator = build_expr_wfl (NULL_TREE, file, 0, 0);
+    wfl_operator = build_expr_wfl (NULL_TREE, (const char *)file, 0, 0);
   else
     EXPR_WFL_FILENAME_NODE (wfl_operator) = file;
   input_filename = ggc_strdup (current_jcf->filename);
Index: jvgenmain.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/jvgenmain.c,v
retrieving revision 1.18
diff -u -p -r1.18 jvgenmain.c
--- jvgenmain.c	2000/12/08 03:00:26	1.18
+++ jvgenmain.c	2001/01/07 15:24:14
@@ -32,8 +32,8 @@ The Free Software Foundation is independ
 #include "tree.h"
 #include "java-tree.h"
 
-const char main_method_prefix[] = "main__";
-const char main_method_suffix[] = "Pt6JArray1ZPQ34java4lang6String";
+static char * do_mangle_classname PARAMS ((const char *string));
+
 const char class_mangling_suffix[] = "class$";
 
 struct obstack name_obstack;
@@ -116,9 +116,7 @@ main (int argc, const char **argv)
   classname = argv[i];
 
   gcc_obstack_init (&name_obstack);
-  append_gpp_mangled_classtype (&name_obstack, classname);
-  obstack_1grow (&name_obstack, '\0');
-  mangled_classname = obstack_finish (&name_obstack);
+  mangled_classname = do_mangle_classname (classname);
 
   if (i < argc - 1 && strcmp (argv[i + 1], "-") != 0)
     {
@@ -156,11 +154,11 @@ main (int argc, const char **argv)
   fprintf (stream, "  0\n};\n\n");
 
 #ifndef NO_DOLLAR_IN_LABEL
-  fprintf (stream, "extern int class __attribute__ ((alias (\"_%s$%s\")));\n",
-	   mangled_classname, class_mangling_suffix);
+  fprintf (stream, "extern int class __attribute__ ((alias (\"%s\")));\n",
+	   mangled_classname);
 #else
-  fprintf (stream, "extern int class __attribute__ ((alias (\"_%s.%s\")));\n",
-	   mangled_classname, class_mangling_suffix);
+  fprintf (stream, "extern int class __attribute__ ((alias (\"%s\")));\n",
+	   mangled_classname);
 #endif
   fprintf (stream, "int main (int argc, const char **argv)\n");
   fprintf (stream, "{\n");
@@ -174,4 +172,37 @@ main (int argc, const char **argv)
       exit (1);
     }
   return 0;
+}
+
+
+static char *
+do_mangle_classname (string)
+     const char *string;
+{
+  char *ptr;
+  int count = 0;
+
+#define MANGLE_NAME()						\
+  {								\
+    char buffer [128];						\
+    sprintf (buffer, "%d", count);				\
+    obstack_grow (&name_obstack, buffer, strlen (buffer));	\
+    obstack_grow (&name_obstack, & ptr [-count], count);	\
+    count = 0;							\
+  }
+
+  obstack_grow (&name_obstack, "_ZN", 3);
+
+  for (ptr = (char *)string; *ptr; ptr++ )
+    {
+      if (ptr[0] == '.')
+	{
+	  MANGLE_NAME ();
+	}
+      else
+	count++;
+    }
+  MANGLE_NAME ();
+  obstack_grow0 (&name_obstack, "6class$E", 8);
+  return obstack_finish (&name_obstack);
 }
Index: lex.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/lex.c,v
retrieving revision 1.55
diff -u -p -r1.55 lex.c
--- lex.c	2000/12/13 22:47:13	1.55
+++ lex.c	2001/01/07 15:24:28
@@ -61,6 +61,10 @@ static int java_read_char PARAMS ((java_
 static void java_allocate_new_line PARAMS ((void));
 static void java_unget_unicode PARAMS ((void));
 static unicode_t java_sneak_unicode PARAMS ((void));
+#ifndef JC1_LITE
+static int utf8_cmp PARAMS ((const unsigned char *, int, const char *));
+#endif
+
 java_lexer *java_new_lexer PARAMS ((FILE *, const char *));
 
 /* This is nonzero if we have initialized `need_byteswap'.  */
@@ -1760,3 +1764,101 @@ java_get_line_col (filename, line, col)
   return obstack_finish (&temporary_obstack);
 #endif
 }
+
+#ifndef JC1_LITE
+static int
+utf8_cmp (str, length, name)
+     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;
+}
+
+/* A sorted list of all C++ keywords.  */
+
+static const char *cxx_keywords[] =
+{
+  "asm",
+  "auto",
+  "bool",
+  "const_cast",
+  "delete",
+  "dynamic_cast",
+  "enum",
+  "explicit",
+  "extern",
+  "friend",
+  "inline",
+  "mutable",
+  "namespace",
+  "overload",
+  "register",
+  "reinterpret_cast",
+  "signed",
+  "sizeof",
+  "static_cast",
+  "struct",
+  "template",
+  "typedef",
+  "typeid",
+  "typename",
+  "typenameopt",
+  "union",
+  "unsigned",
+  "using",
+  "virtual",
+  "volatile",
+  "wchar_t"
+};
+
+/* Return true if NAME is a C++ keyword.  */
+
+int
+cxx_keyword_p (name, length)
+     const char *name;
+     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 (name, min_length, cxx_keywords[mid]);
+
+      if (r == 0)
+	{
+	  int i;
+	  /* We've found a match if all the remaining characters are
+	     `$'.  */
+	  for (i = min_length; i < length && name[i] == '$'; ++i)
+	    ;
+	  if (i == length)
+	    return 1;
+	  r = 1;
+	}
+
+      if (r < 0)
+	last = mid;
+      else
+	first = mid;
+    }
+  return 0;
+}
+#endif /* JC1_LITE */
Index: mangle.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/mangle.c,v
retrieving revision 1.10
diff -u -p -r1.10 mangle.c
--- mangle.c	2000/03/14 05:01:04	1.10
+++ mangle.c	2001/01/07 15:24:36
@@ -32,12 +32,225 @@ The Free Software Foundation is independ
 #include "java-tree.h"
 #include "obstack.h"
 #include "toplev.h"
+#include "obstack.h"
+#include "ggc.h"
 
+static void mangle_field_decl PARAMS ((tree));
+static void mangle_method_decl PARAMS ((tree));
+
+static void mangle_type PARAMS ((tree));
+static void mangle_pointer_type PARAMS ((tree));
+static void mangle_array_type PARAMS ((tree));
+static int  mangle_record_type PARAMS ((tree, int));
+
+static int find_compression_pointer_match PARAMS ((tree));
+static int find_compression_array_match PARAMS ((tree));
+static int find_compression_record_match PARAMS ((tree, tree *));
+static int find_compression_array_template_match PARAMS ((tree));
+
+static void set_type_package_list PARAMS ((tree));
+static int  entry_match_pointer_p PARAMS ((tree, int));
+static void emit_compression_string PARAMS ((int));
+
+static void init_mangling PARAMS ((struct obstack *));
+static tree finish_mangling PARAMS ((void));
+static void compression_table_add PARAMS ((tree));
+
+static void append_unicode_mangled_name PARAMS ((const char *, int));
+static void append_gpp_mangled_name PARAMS ((const char *, int));
+static int  unicode_mangling_length PARAMS ((const char *, int));
+static int  mangle_member_name PARAMS ((tree));
+
+/* We use an incoming obstack, always to be provided to the interface
+   functions. */
+struct obstack *mangle_obstack;
+#define MANGLE_RAW_STRING(S) \
+  obstack_grow (mangle_obstack, (S), sizeof (S)-1)
+
+/* This is the mangling interface: a decl, a class field (.class) and
+   the vtable. */
+
+tree
+java_mangle_decl (obstack, decl)
+     struct obstack *obstack;
+     tree decl;
+{
+  init_mangling (obstack);
+  switch (TREE_CODE (decl))
+    {
+    case VAR_DECL:
+      mangle_field_decl (decl);
+      break;
+    case FUNCTION_DECL:
+      mangle_method_decl (decl);
+      break;
+    default:
+      fatal ("Can't mangle `%s\' -- java_mangle_decl", 
+	     tree_code_name [TREE_CODE (decl)]);
+    }
+  return finish_mangling ();
+}
+
+tree 
+java_mangle_class_field (obstack, type)
+     struct obstack *obstack;
+     tree type;
+{
+  init_mangling (obstack);
+  mangle_record_type (type, /* from_pointer = */ 0);
+  MANGLE_RAW_STRING ("6class$");
+  obstack_1grow (mangle_obstack, 'E');
+  return finish_mangling ();
+}
+
+tree
+java_mangle_vtable (obstack, type)
+     struct obstack *obstack;
+     tree type;
+{
+  init_mangling (obstack);
+  MANGLE_RAW_STRING ("TV");
+  mangle_record_type (type, /* from_pointer = */ 0);
+  obstack_1grow (mangle_obstack, 'E');
+  return finish_mangling ();
+}
+
+/* Beginning of the helper functions */
+
+/* This mangles a field decl */
+
+static void
+mangle_field_decl (decl)
+     tree decl;
+{
+  tree name = DECL_NAME (decl);
+  int encoded_len;
+#if 0				/* DONT KNOW WHAT TO DO WITH THIS FIXME */
+#if ! defined (NO_DOLLAR_IN_LABEL) || ! defined (NO_DOT_IN_LABEL)
+  obstack_1grow (mangle_obstack, '_');
+#else
+  obstack_grow (mangle_obstack, "__static_", 9);
+#endif
+#endif
+
+  /* Mangle the name of the this the field belongs to */
+  mangle_record_type (DECL_CONTEXT (decl), /* from_pointer = */ 0);
+  
+  /* Mangle the name of the field */
+  encoded_len = unicode_mangling_length (IDENTIFIER_POINTER (name),
+					 IDENTIFIER_LENGTH (name));
+
+  /* I DON'T WHAT OF BELOW IS NECESSARY: unicode and $ business FIXME */
+  if (encoded_len > 0)
+    obstack_1grow (mangle_obstack, 'U');
+#if 0
+#ifndef NO_DOLLAR_IN_LABEL
+  obstack_1grow (mangle_obstack, '$');
+#else /* NO_DOLLAR_IN_LABEL */
+#ifndef NO_DOT_IN_LABEL
+  obstack_1grow (mangle_obstack, '.');
+#else /* NO_DOT_IN_LABEL */
+  obstack_1grow (mangle_obstack, '_');
+#endif  /* NO_DOT_IN_LABEL */
+#endif  /* NO_DOLLAR_IN_LABEL */
+#endif
+  mangle_member_name (name);
+
+  /* Mangle C++ keywords by appending a `$'.  */
+  /* FIXME: NO_DOLLAR_IN_LABEL */
+  if (cxx_keyword_p (IDENTIFIER_POINTER (name), IDENTIFIER_LENGTH (name)))
+    obstack_grow (mangle_obstack, "$", 1);
+  obstack_1grow (mangle_obstack, 'E');
+}
+
+/* This mangles a method decl, first mangling its name and then all
+   its arguments. */
+
+static void
+mangle_method_decl (mdecl)
+     tree mdecl;
+{
+  tree method_name = DECL_NAME (mdecl);
+  tree arglist;
+  int method_name_needs_escapes = 0;
+
+  /* Mangle the name of the type that contains mdecl */
+  mangle_record_type (DECL_CONTEXT (mdecl), /* from_pointer = */ 0);
+
+  /* Before working on the method name, get to it. It might be burried
+     in a WFL. */
+  if (TREE_CODE (method_name) == EXPR_WITH_FILE_LOCATION)
+    method_name = java_get_real_method_name (mdecl);
+
+  if (!strcmp (method_name->identifier.pointer, "FOO"))
+    printf ("FOO\n");
+
+  /* Mangle the function name. There three cases
+     - mdecl is java.lang.Object.Object(), use `C2' for its name
+       (denotes a base object constructor.)
+     - mdecl is a constructor, use `C1' for its name, (denotes a
+       complete object constructor.)
+     - mdecl is not a constructor, standard mangling is performed. */
+  if (ID_INIT_P (method_name))
+    {
+    if (DECL_CONTEXT (mdecl) == object_type_node)
+      obstack_grow (mangle_obstack, "C2", 2);
+    else
+      obstack_grow (mangle_obstack, "C1", 2);
+    }
+  else
+    {
+      method_name_needs_escapes = mangle_member_name (method_name);
+      /* Mangle C++ keywords by appending a `$'.  */
+      /* FIXME: NO_DOLLAR_IN_LABEL */
+      if (cxx_keyword_p (IDENTIFIER_POINTER (method_name),
+			 IDENTIFIER_LENGTH (method_name)))
+	obstack_grow (mangle_obstack, "$", 1);
+    }
+  obstack_1grow (mangle_obstack, 'E');
+
+  /* We mangling type.methodName. Now onto the arguments. */
+  arglist = TYPE_ARG_TYPES (TREE_TYPE (mdecl));
+  if (TREE_CODE (TREE_TYPE (mdecl)) == METHOD_TYPE)
+    arglist = TREE_CHAIN (arglist);
+  
+  /* No arguments is easy. We shortcut it. */
+  if (arglist == end_params_node)
+    obstack_1grow (mangle_obstack, 'v');
+  else
+    {
+      tree arg;
+      for (arg = arglist; arg != end_params_node;  arg = TREE_CHAIN (arg))
+	mangle_type (TREE_VALUE (arg));
+    }
+  if (method_name_needs_escapes)
+    obstack_1grow (mangle_obstack, 'U');
+}
+
+/* This mangles a member name, like a function name or a field
+   name. */
+
+static int
+mangle_member_name (name)
+     tree name;
+{
+  const char * name_string = IDENTIFIER_POINTER (name);
+  int len = IDENTIFIER_LENGTH (name);
+
+  if (unicode_mangling_length (name_string, len) > 0)
+    {
+      append_unicode_mangled_name (name_string, len);
+      return 1;
+    }
+  append_gpp_mangled_name (name_string, len);
+  return 0;
+}
+
 /* Assuming (NAME, LEN) is a Utf8-encoding string, calculate
    the length of the string as mangled (a la g++) including Unicode escapes.
    If no escapes are needed, return 0. */
 
-int
+static int
 unicode_mangling_length (name, len)
      const char *name; 
      int len; 
@@ -69,9 +282,8 @@ unicode_mangling_length (name, len)
 /* Assuming (NAME, LEN) is a Utf8-encoding string, emit the string
    appropriately mangled (with Unicode escapes) to OBSTACK. */
 
-void
-emit_unicode_mangled_name (obstack, name, len)
-     struct obstack *obstack;
+static void
+append_unicode_mangled_name (name, len)
      const char *name;
      int len;
 {
@@ -94,11 +306,11 @@ emit_unicode_mangled_name (obstack, name
 	{
 	  char buf[6];
 	  sprintf (buf, "_%04x", ch);
-	  obstack_grow (obstack, buf, 5);
+	  obstack_grow (mangle_obstack, buf, 5);
 	}
       else
 	{
-	  obstack_1grow (obstack, ch);
+	  obstack_1grow (mangle_obstack, ch);
 	}
     }
 }
@@ -106,9 +318,8 @@ emit_unicode_mangled_name (obstack, name
 /* Assuming (NAME, LEN) is a Utf8-encoding string, emit the string
    appropriately mangled (with Unicode escapes if needed) to OBSTACK. */
 
-void
-append_gpp_mangled_name (obstack, name, len)
-     struct obstack *obstack;
+static void
+append_gpp_mangled_name (name, len)
      const char *name;
      int len;
 {
@@ -118,49 +329,466 @@ append_gpp_mangled_name (obstack, name, 
   if (needs_escapes)
     {
       sprintf (buf, "U%d", encoded_len);
-      obstack_grow (obstack, buf, strlen(buf));
-      emit_unicode_mangled_name (obstack, name, len);
+      obstack_grow (mangle_obstack, buf, strlen(buf));
+      append_unicode_mangled_name (name, len);
     }
   else
     {
       sprintf (buf, "%d", len);
-      obstack_grow (obstack, buf, strlen(buf));
-      obstack_grow (obstack, name, len);
+      obstack_grow (mangle_obstack, buf, strlen(buf));
+      obstack_grow (mangle_obstack, name, len);
     }
 }
 
-/* Append the mangled name of a class named CLASSNAME onto OBSTACK. */
+/* Append the mangled name of TYPE onto OBSTACK.  */
 
-void
-append_gpp_mangled_classtype (obstack, class_name)
-     struct obstack *obstack;
-     const char *class_name;
+static void
+mangle_type (type)
+     tree type;
 {
-  const char *ptr;
-  int qualifications = 0;
+  switch (TREE_CODE (type))
+    {
+      char code;
+    case BOOLEAN_TYPE: code = 'b';  goto primitive;
+    case CHAR_TYPE:    code = 'w';  goto primitive;
+    /* DO WE NEED THIS? FIXME */
+    case VOID_TYPE:    code = 'v';  goto primitive;
+    case INTEGER_TYPE:
+      /* Get the original type instead of the arguments promoted type.
+	 Avoid symbol name clashes. Should call a function to do that.
+	 FIXME.  */
+      if (type == promoted_short_type_node)
+	type = short_type_node;
+      if (type == promoted_byte_type_node)
+        type = byte_type_node;
+      switch (TYPE_PRECISION (type))
+	{
+	case  8:       code = 'c';  goto primitive;
+	case 16:       code = 's';  goto primitive;
+	case 32:       code = 'i';  goto primitive;
+	case 64:       code = 'x';  goto primitive;
+	default:  goto bad_type;
+	}
+    primitive:
+      obstack_1grow (mangle_obstack, code);
+      break;
 
-  for (ptr = class_name; *ptr != '\0'; ptr++)
+    case REAL_TYPE:
+      switch (TYPE_PRECISION (type))
+	{
+	case 32:       code = 'f';  goto primitive;
+	case 64:       code = 'd';  goto primitive;
+	default:  goto bad_type;
+	}
+    case RECORD_TYPE:
+      /* We should replace this by a fatal. This shouldn't occurs. FIXME */
+      if (mangle_record_type (type, /* from_pointer = */ 1))
+	obstack_1grow (mangle_obstack, 'E');
+      break;
+    case POINTER_TYPE:
+      if (TYPE_ARRAY_P (TREE_TYPE (type)))
+	mangle_array_type (type);
+      else
+	mangle_pointer_type (type);
+      break;
+    bad_type:
+    default:
+      fatal ("internal error - trying to mangle unknown type");
+    }
+}
+
+/* The compression table is a vector that keeps track of things we've
+   already seen, so they can be reused. For example, java.lang.Object
+   Would generate three entries: two package names and a type. If
+   java.lang.String is presented next, the java.lang will be matched
+   against the first two entries (and kept for compression as S_0), and
+   type String would be added to the table. See mangle_record_type.
+   COMPRESSION_NEXT is the index to the location of the next insertion
+   of an element.  */
+
+tree compression_table;
+int  compression_next;
+
+/* Find a POINTER_TYPE in the compression table. Use a special
+   function to match pointer entries and start from the end */
+
+static int
+find_compression_pointer_match (type)
+     tree type;
+{
+  int i;
+
+  for (i = compression_next-1; i >= 0; i--)
+    if (entry_match_pointer_p (type, i))
+      return i;
+  return -1;
+}
+
+/* Already recorder arrays are handled like pointer as they're always
+   associated with it.  */
+
+static int
+find_compression_array_match (type)
+     tree type;
+{
+  return find_compression_pointer_match (type);
+}
+
+/* Match the table of type against STRING.  */
+
+static int
+find_compression_array_template_match (string)
+     tree string;
+{
+  int i;
+  for (i = 0; i < compression_next; i++)
+    if (TREE_VEC_ELT (compression_table, i) == string) 
+      return i;
+  return -1;
+}
+
+/* We go through the compression table and try to find a complete or
+   partial match. The function returns the compression table entry
+   that (evenutally partially) matches TYPE. *NEXT_CURRENT can be set
+   to the rest of TYPE to be mangled. */
+
+static int
+find_compression_record_match (type, next_current)
+     tree type;
+     tree *next_current;
+{
+  int i, match;
+  tree current, saved_current;
+
+  /* Search from the beginning for something that matches TYPE, even
+     partially. */
+  for (current = TYPE_PACKAGE_LIST (type), i = 0, match = -1; current;
+       current = TREE_CHAIN (current))
     {
-      if (*ptr == '.')
-	qualifications++;
+      int j;
+      for (j = i; j < compression_next; j++)
+	if (TREE_VEC_ELT (compression_table, j) == TREE_PURPOSE (current))
+	  {
+	    match = i = j;
+	    saved_current = current;
+	    break;
+	  }
     }
-  if (qualifications)
+
+  if (!next_current)
+    return match;
+
+  /* If we have a match, set next_current to the item next to the last
+     matched value. */
+  if (match >= 0)
+    *next_current = TREE_CHAIN (saved_current);
+  /* We had no match: we'll have to start from the beginning. */
+  if (match < 0)
+    *next_current = TYPE_PACKAGE_LIST (type);
+
+  return match;
+}
+
+/* Mangle a record type. If a non zero value is returned, it means
+   that a 'N' was emitted (so that a matching 'E' can be emitted if
+   necessary.)  */
+
+static int
+mangle_record_type (type, from_pointer)
+     tree type;
+     int from_pointer;
+{
+  tree current;
+  int match;
+  int nadded_p = 0;
+
+#define ADD_N() \
+  do { obstack_1grow (mangle_obstack, 'N'); nadded_p = 1; } while (0)
+
+  if (TREE_CODE (type) != RECORD_TYPE)
+    fatal ("Non RECORD_TYPE argument -- mangle_record_type");
+
+  if (!TYPE_PACKAGE_LIST (type))
+    set_type_package_list (type);
+
+  match = find_compression_record_match (type, &current);
+  if (match >= 0)
     {
-      char buf[8];
-      if (qualifications >= 9)
-	sprintf (buf, "Q_%d_", qualifications + 1);
-      else
-	sprintf (buf, "Q%d", qualifications + 1);
-      obstack_grow (obstack, buf, strlen (buf));
+      /* If we had a pointer, and there's more, we need to emit
+	 'N' after 'P' (from pointer tells us we already emitted it.) */
+      if (from_pointer && current)
+	ADD_N();
+      emit_compression_string (match);
     }
-  for (ptr = class_name; ; ptr++)
+  while (current)
     {
-      if (ptr[0] == '.' || ptr[0] == '\0')
+      /* Add the new type to the table */
+      compression_table_add (TREE_PURPOSE (current));
+      /* Add 'N' if we never got a chance to. */
+      if (!nadded_p)
+	ADD_N();
+      /* Use the bare type name for the mangle. */
+      append_gpp_mangled_name (IDENTIFIER_POINTER (TREE_VALUE (current)),
+			       IDENTIFIER_LENGTH (TREE_VALUE (current)));
+      current = TREE_CHAIN (current);
+    }
+  return nadded_p;
+#undef ADD_N
+}
+
+/* Mangle a pointer type. There are two cases: the pointer is already
+   in the compression table: the compression is emited sans 'P'
+   indicator. Otherwise, a 'P' is emitted and, depending on the type,
+   a partial compression or/plus the rest of the mangling. */
+
+static void
+mangle_pointer_type (type)
+     tree type;
+{
+  int match;
+  tree pointer_type;
+
+  /* Search for the type already in the compression table */
+  if ((match = find_compression_pointer_match (type)) >= 0) 
+    {
+      emit_compression_string (match);
+      return;
+    }
+  
+  /* This didn't work. We start by mangling the pointed-to type */
+  pointer_type = type;
+  type = TREE_TYPE (type);
+  if (TREE_CODE (type) != RECORD_TYPE)
+    fatal ("Double indirection found -- mangle_pointer_type");
+  
+  obstack_1grow (mangle_obstack, 'P');
+  if (mangle_record_type (type, /* for_pointer = */ 1))
+    obstack_1grow (mangle_obstack, 'E');
+
+  /* Don't forget to insert the pointer type in the table */
+  compression_table_add (pointer_type);
+}
+
+/* Mangle an array type. Search for an easy solution first, then go
+   through the process of finding out whether the bare array type or even
+   the template indicator where already used an compress appropriately.
+   It handles pointers. */
+
+static void
+mangle_array_type (p_type)
+     tree p_type;
+{
+  /* atms: array template mangled string. */
+  static tree atms = NULL_TREE;
+  tree type, elt_type;
+  int match;
+
+  type = TREE_TYPE (p_type);
+  if (!type)
+    fatal ("Non pointer array type -- mangle_array_type");
+  elt_type = TYPE_ARRAY_ELEMENT (type);
+
+  /* We cache a bit of the Jarray <> mangle. */
+  if (!atms)
+    {
+      atms = get_identifier ("6JArray");
+      ggc_add_tree_root (&atms, 1);
+    }
+
+  /* Maybe we have what we're looking in the compression table. */
+  if ((match = find_compression_array_match (p_type)) >= 0)
+    {
+      emit_compression_string (match);
+      return;
+    }
+
+  /* We know for a fact that all arrays are pointers */
+  obstack_1grow (mangle_obstack, 'P');
+  /* Maybe we already have a Jarray<t> somewhere. PSx_ will be enough. */
+  if ((match = find_compression_record_match (type, NULL)) > 0)
+    {
+      emit_compression_string (match);
+      return;
+    }
+
+  /* Maybe we already have just JArray somewhere */
+  if ((match = find_compression_array_template_match (atms)) > 0)
+    emit_compression_string (match);
+  else
+    {
+      /* Start the template mangled name */
+      obstack_grow (mangle_obstack, 
+		    IDENTIFIER_POINTER (atms), IDENTIFIER_LENGTH (atms));
+      /* Insert in the compression table */
+      compression_table_add (atms);
+    } 
+
+  /* Mangle Jarray <elt_type> */
+  obstack_1grow (mangle_obstack, 'I');
+  mangle_type (elt_type);
+  obstack_1grow (mangle_obstack, 'E');
+
+  /* Add `Jarray <elt_type>' and `Jarray <elt_type> *' to the table */
+  compression_table_add (type);
+  compression_table_add (p_type);
+}
+
+/* Write a substition string for entry I. Substitution string starts a
+   -1 (encoded S_.) The base is 36, and the code shamlessly taken from
+   cp/mangle.c.  */
+
+static void
+emit_compression_string (int i)
+{
+  i -= 1;			/* Adjust */
+  obstack_1grow (mangle_obstack, 'S');
+  if (i >= 0)
+    {
+      static const char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+      unsigned HOST_WIDE_INT n;
+      unsigned HOST_WIDE_INT m=1;
+      /* How many digits for I in base 36? */
+      for (n = i; n >= 36; n /= 36, m *=36);
+      /* Write the digits out */
+      while (m > 0)
 	{
-	  append_gpp_mangled_name (obstack, class_name, ptr - class_name);
-	  if (ptr[0] == '\0')
-	    break;
-	  class_name = ptr + 1;
+	  int digit = i / m;
+	  obstack_1grow (mangle_obstack, digits [digit]);
+	  i -= digit * m;
+	  m /= 36;
 	}
     }
+  obstack_1grow (mangle_obstack, '_');
+}
+
+/* If search the compression table at index I for a pointer type
+   equivalent to TYPE (meaning that after all the indirection, which
+   might all be unique, we find the same RECORD_TYPE.) */
+
+static int
+entry_match_pointer_p (type, i)
+     tree type;
+     int i;
+{
+  tree t = TREE_VEC_ELT (compression_table, i);
+  
+  while (TREE_CODE (type) == POINTER_TYPE
+	 && TREE_CODE (t) == POINTER_TYPE)
+    {
+      t = TREE_TYPE (t);
+      type = TREE_TYPE (type);
+    }
+  return (TREE_CODE (type) == RECORD_TYPE
+	  && TREE_CODE (t) == RECORD_TYPE
+	  && t == type);
+}
+
+/* Go through all qualification of type and build a list of list node
+   elements containings as a purpose what should be used for a match and
+   inserted in the compression table; and as it value the raw name of the
+   part. The result is stored in TYPE_PACKAGE_LIST to be reused.  */
+
+static void
+set_type_package_list (type)
+     tree type;
+{
+  int i;
+  const char *type_string = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
+  char *ptr;
+  int qualifications;
+  tree list = NULL_TREE, elt;
+
+  for (ptr = (char *)type_string, qualifications = 0; *ptr; ptr++)
+    if (*ptr == '.')
+      qualifications += 1;
+
+  for (ptr = (char *)type_string, i = 0; i < qualifications; ptr++)
+    {
+      if (ptr [0] == '.')
+	{
+	  char c;
+	  tree identifier;
+
+	  /* Can't use an obstack, we're already using it to
+	     accumulate the mangling. */
+	  c = ptr [0];
+	  ptr [0] = '\0';
+	  identifier = get_identifier (type_string);
+	  ptr [0] = c;
+	  elt = build_tree_list (identifier, identifier);
+	  TREE_CHAIN (elt) = list;
+	  list = elt;
+	  type_string = ptr+1;
+	  i += 1;
+	}
+    }
+
+  elt = build_tree_list (type, get_identifier (type_string));
+  TREE_CHAIN (elt) = list;
+  list = elt;
+  TYPE_PACKAGE_LIST (type) = nreverse (list);
+}
+
+/* Add TYPE as the last element of the compression table. Resize the
+   compression table if necessary.  */
+
+static void
+compression_table_add (type)
+     tree type;
+{
+  if (compression_next == TREE_VEC_LENGTH (compression_table))
+    {
+      tree new = make_tree_vec (2*compression_next);
+      int i;
+
+      for (i = 0; i < compression_next; i++)
+	TREE_VEC_ELT (new, i) = TREE_VEC_ELT (compression_table, i);
+
+      ggc_del_root (&compression_table);
+      compression_table = new;
+      ggc_add_tree_root (&compression_table, 1);
+    }
+  TREE_VEC_ELT (compression_table, compression_next++) = type;
+}
+
+/* Mangling initialization routine.  */
+
+static void
+init_mangling (obstack)
+     struct obstack *obstack;
+{
+  mangle_obstack = obstack;
+  if (!compression_table)
+    compression_table = make_tree_vec (10);
+  else
+    fatal ("Mangling already in progress -- init_mangling");
+
+  /* Mangled name are to be suffixed */
+  obstack_grow (mangle_obstack, "_Z", 2);
+
+  /* Register the compression table with the GC */
+  ggc_add_tree_root (&compression_table, 1);
+}
+
+/* Mangling finalization routine. The mangled name is returned as a
+   IDENTIFIER_NODE.  */
+
+static tree
+finish_mangling ()
+{
+  tree result;
+
+  if (!compression_table)
+    fatal ("Mangling already finished -- finish_mangling");
+
+  ggc_del_root (&compression_table);
+  compression_table = NULL_TREE;
+  compression_next = 0;
+  obstack_1grow (mangle_obstack, '\0');
+  result = get_identifier (obstack_base (mangle_obstack));
+  obstack_free (mangle_obstack, obstack_base (mangle_obstack));
+#if 0
+  printf ("// %s\n", IDENTIFIER_POINTER (result));
+#endif
+  return result;
 }
Index: parse.y
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/parse.y,v
retrieving revision 1.238
diff -u -p -r1.238 parse.y
--- parse.y	2000/12/18 21:23:02	1.238
+++ parse.y	2001/01/07 15:27:53
@@ -2973,7 +2973,6 @@ yyerror (msg)
 
   int save_lineno;
   char *remainder, *code_from_source;
-  extern struct obstack temporary_obstack;
   
   if (!force_error && prev_lineno == lineno)
     return;


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]