1 /* Functions related to mangling class names for the GNU compiler
2 for the Java(TM) language.
3 Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc.
5 This file is part of GNU CC.
7 GNU CC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU CC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU CC; see the file COPYING. If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
22 Java and all Java-based marks are trademarks or registered trademarks
23 of Sun Microsystems, Inc. in the United States and other countries.
24 The Free Software Foundation is independent of Sun Microsystems, Inc. */
26 /* Written by Per Bothner <bothner@cygnus.com> */
32 #include "java-tree.h"
38 static void mangle_field_decl PARAMS ((tree));
39 static void mangle_method_decl PARAMS ((tree));
41 static void mangle_type PARAMS ((tree));
42 static void mangle_pointer_type PARAMS ((tree));
43 static void mangle_array_type PARAMS ((tree));
44 static int mangle_record_type PARAMS ((tree, int));
46 static int find_compression_pointer_match PARAMS ((tree));
47 static int find_compression_array_match PARAMS ((tree));
48 static int find_compression_record_match PARAMS ((tree, tree *));
49 static int find_compression_array_template_match PARAMS ((tree));
51 static void set_type_package_list PARAMS ((tree));
52 static int entry_match_pointer_p PARAMS ((tree, int));
53 static void emit_compression_string PARAMS ((int));
55 static void init_mangling PARAMS ((struct obstack *));
56 static tree finish_mangling PARAMS ((void));
57 static void compression_table_add PARAMS ((tree));
59 static void mangle_member_name PARAMS ((tree));
61 /* We use an incoming obstack, always to be provided to the interface
63 struct obstack *mangle_obstack;
64 #define MANGLE_RAW_STRING(S) \
65 obstack_grow (mangle_obstack, (S), sizeof (S)-1)
67 /* This is the mangling interface: a decl, a class field (.class) and
71 java_mangle_decl (obstack, decl)
72 struct obstack *obstack;
75 init_mangling (obstack);
76 switch (TREE_CODE (decl))
79 mangle_field_decl (decl);
82 mangle_method_decl (decl);
85 internal_error ("Can't mangle %s", tree_code_name [TREE_CODE (decl)]);
87 return finish_mangling ();
91 java_mangle_class_field (obstack, type)
92 struct obstack *obstack;
95 init_mangling (obstack);
96 mangle_record_type (type, /* for_pointer = */ 0);
97 MANGLE_RAW_STRING ("6class$");
98 obstack_1grow (mangle_obstack, 'E');
99 return finish_mangling ();
103 java_mangle_vtable (obstack, type)
104 struct obstack *obstack;
107 init_mangling (obstack);
108 MANGLE_RAW_STRING ("TV");
109 mangle_record_type (type, /* for_pointer = */ 0);
110 obstack_1grow (mangle_obstack, 'E');
111 return finish_mangling ();
114 /* Beginning of the helper functions */
116 /* This mangles a field decl */
119 mangle_field_decl (decl)
122 /* Mangle the name of the this the field belongs to */
123 mangle_record_type (DECL_CONTEXT (decl), /* for_pointer = */ 0);
125 /* Mangle the name of the field */
126 mangle_member_name (DECL_NAME (decl));
128 /* Terminate the mangled name */
129 obstack_1grow (mangle_obstack, 'E');
132 /* This mangles a method decl, first mangling its name and then all
136 mangle_method_decl (mdecl)
139 tree method_name = DECL_NAME (mdecl);
142 /* Mangle the name of the type that contains mdecl */
143 mangle_record_type (DECL_CONTEXT (mdecl), /* for_pointer = */ 0);
145 /* Mangle the function name. There three cases
146 - mdecl is java.lang.Object.Object(), use `C2' for its name
147 (denotes a base object constructor.)
148 - mdecl is a constructor, use `C1' for its name, (denotes a
149 complete object constructor.)
150 - mdecl is not a constructor, standard mangling is performed.
151 We terminate the mangled function name with a `E'. */
152 if (ID_INIT_P (method_name))
154 if (DECL_CONTEXT (mdecl) == object_type_node)
155 obstack_grow (mangle_obstack, "C2", 2);
157 obstack_grow (mangle_obstack, "C1", 2);
160 mangle_member_name (method_name);
161 obstack_1grow (mangle_obstack, 'E');
163 /* We mangled type.methodName. Now onto the arguments. */
164 arglist = TYPE_ARG_TYPES (TREE_TYPE (mdecl));
165 if (TREE_CODE (TREE_TYPE (mdecl)) == METHOD_TYPE)
166 arglist = TREE_CHAIN (arglist);
168 /* No arguments is easy. We shortcut it. */
169 if (arglist == end_params_node)
170 obstack_1grow (mangle_obstack, 'v');
174 for (arg = arglist; arg != end_params_node; arg = TREE_CHAIN (arg))
175 mangle_type (TREE_VALUE (arg));
179 /* This mangles a member name, like a function name or a field
180 name. Handle cases were `name' is a C++ keyword. Return a non zero
181 value if unicode encoding was required. */
184 mangle_member_name (name)
187 append_gpp_mangled_name (IDENTIFIER_POINTER (name),
188 IDENTIFIER_LENGTH (name));
190 /* If NAME happens to be a C++ keyword, add `$' or `.' or `_'. */
191 if (cxx_keyword_p (IDENTIFIER_POINTER (name), IDENTIFIER_LENGTH (name)))
193 #ifndef NO_DOLLAR_IN_LABEL
194 obstack_1grow (mangle_obstack, '$');
195 #else /* NO_DOLLAR_IN_LABEL */
196 #ifndef NO_DOT_IN_LABEL
197 obstack_1grow (mangle_obstack, '.');
198 #else /* NO_DOT_IN_LABEL */
199 obstack_1grow (mangle_obstack, '_');
200 #endif /* NO_DOT_IN_LABEL */
201 #endif /* NO_DOLLAR_IN_LABEL */
205 /* Append the mangled name of TYPE onto OBSTACK. */
211 switch (TREE_CODE (type))
214 case BOOLEAN_TYPE: code = 'b'; goto primitive;
215 case CHAR_TYPE: code = 'w'; goto primitive;
216 case VOID_TYPE: code = 'v'; goto primitive;
218 /* Get the original type instead of the arguments promoted type.
219 Avoid symbol name clashes. Should call a function to do that.
221 if (type == promoted_short_type_node)
222 type = short_type_node;
223 if (type == promoted_byte_type_node)
224 type = byte_type_node;
225 switch (TYPE_PRECISION (type))
227 case 8: code = 'c'; goto primitive;
228 case 16: code = 's'; goto primitive;
229 case 32: code = 'i'; goto primitive;
230 case 64: code = 'x'; goto primitive;
231 default: goto bad_type;
234 obstack_1grow (mangle_obstack, code);
238 switch (TYPE_PRECISION (type))
240 case 32: code = 'f'; goto primitive;
241 case 64: code = 'd'; goto primitive;
242 default: goto bad_type;
245 if (TYPE_ARRAY_P (TREE_TYPE (type)))
246 mangle_array_type (type);
248 mangle_pointer_type (type);
256 /* The compression table is a vector that keeps track of things we've
257 already seen, so they can be reused. For example, java.lang.Object
258 would generate three entries: two package names and a type. If
259 java.lang.String is presented next, the java.lang will be matched
260 against the first two entries (and kept for compression as S_0), and
261 type String would be added to the table. See mangle_record_type.
262 COMPRESSION_NEXT is the index to the location of the next insertion
265 static tree compression_table;
266 static int compression_next;
268 /* Find a POINTER_TYPE in the compression table. Use a special
269 function to match pointer entries and start from the end */
272 find_compression_pointer_match (type)
277 for (i = compression_next-1; i >= 0; i--)
278 if (entry_match_pointer_p (type, i))
283 /* Already recorder arrays are handled like pointer as they're always
284 associated with it. */
287 find_compression_array_match (type)
290 return find_compression_pointer_match (type);
293 /* Match the table of type against STRING. */
296 find_compression_array_template_match (string)
300 for (i = 0; i < compression_next; i++)
301 if (TREE_VEC_ELT (compression_table, i) == string)
306 /* We go through the compression table and try to find a complete or
307 partial match. The function returns the compression table entry
308 that (evenutally partially) matches TYPE. *NEXT_CURRENT can be set
309 to the rest of TYPE to be mangled. */
312 find_compression_record_match (type, next_current)
317 tree current, saved_current = NULL_TREE;
319 /* Search from the beginning for something that matches TYPE, even
321 for (current = TYPE_PACKAGE_LIST (type), i = 0, match = -1; current;
322 current = TREE_CHAIN (current))
325 for (j = i; j < compression_next; j++)
326 if (TREE_VEC_ELT (compression_table, j) == TREE_PURPOSE (current))
329 saved_current = current;
335 /* We don't want to match an element that appears in the middle
336 of a package name, so skip forward to the next complete type name.
337 IDENTIFIER_NODEs are partial package names while RECORD_TYPEs
338 represent complete type names. */
339 while (j < compression_next
340 && TREE_CODE (TREE_VEC_ELT (compression_table, j)) ==
349 /* If we have a match, set next_current to the item next to the last
352 *next_current = TREE_CHAIN (saved_current);
353 /* We had no match: we'll have to start from the beginning. */
355 *next_current = TYPE_PACKAGE_LIST (type);
360 /* Mangle a record type. If a non zero value is returned, it means
361 that a 'N' was emitted (so that a matching 'E' can be emitted if
362 necessary.) FOR_POINTER indicates that this element is for a pointer
363 symbol, meaning it was preceded by a 'P'. */
366 mangle_record_type (type, for_pointer)
375 /* Does this name have a package qualifier? */
376 qualified = QUALIFIED_P (DECL_NAME (TYPE_NAME (type)));
379 do { obstack_1grow (mangle_obstack, 'N'); nadded_p = 1; } while (0)
381 if (TREE_CODE (type) != RECORD_TYPE)
384 if (!TYPE_PACKAGE_LIST (type))
385 set_type_package_list (type);
387 match = find_compression_record_match (type, ¤t);
390 /* If we had a pointer, and there's more, we need to emit
391 'N' after 'P' (for_pointer tells us we already emitted it.) */
392 if (for_pointer && current)
394 emit_compression_string (match);
398 /* Add the new type to the table */
399 compression_table_add (TREE_PURPOSE (current));
400 /* Add 'N' if we never got a chance to, but only if we have a qualified
401 name. For non-pointer elements, the name is always qualified. */
402 if ((qualified || !for_pointer) && !nadded_p)
404 /* Use the bare type name for the mangle. */
405 append_gpp_mangled_name (IDENTIFIER_POINTER (TREE_VALUE (current)),
406 IDENTIFIER_LENGTH (TREE_VALUE (current)));
407 current = TREE_CHAIN (current);
413 /* Mangle a pointer type. There are two cases: the pointer is already
414 in the compression table: the compression is emited sans 'P'
415 indicator. Otherwise, a 'P' is emitted and, depending on the type,
416 a partial compression or/plus the rest of the mangling. */
419 mangle_pointer_type (type)
425 /* Search for the type already in the compression table */
426 if ((match = find_compression_pointer_match (type)) >= 0)
428 emit_compression_string (match);
432 /* This didn't work. We start by mangling the pointed-to type */
434 type = TREE_TYPE (type);
435 if (TREE_CODE (type) != RECORD_TYPE)
438 obstack_1grow (mangle_obstack, 'P');
439 if (mangle_record_type (type, /* for_pointer = */ 1))
440 obstack_1grow (mangle_obstack, 'E');
442 /* Don't forget to insert the pointer type in the table */
443 compression_table_add (pointer_type);
446 /* Mangle an array type. Search for an easy solution first, then go
447 through the process of finding out whether the bare array type or even
448 the template indicator where already used an compress appropriately.
449 It handles pointers. */
452 mangle_array_type (p_type)
455 /* atms: array template mangled string. */
456 static tree atms = NULL_TREE;
460 type = TREE_TYPE (p_type);
464 elt_type = TYPE_ARRAY_ELEMENT (type);
466 /* We cache a bit of the Jarray <> mangle. */
469 atms = get_identifier ("6JArray");
470 ggc_add_tree_root (&atms, 1);
473 /* Maybe we have what we're looking in the compression table. */
474 if ((match = find_compression_array_match (p_type)) >= 0)
476 emit_compression_string (match);
480 /* We know for a fact that all arrays are pointers */
481 obstack_1grow (mangle_obstack, 'P');
482 /* Maybe we already have a Jarray<t> somewhere. PSx_ will be enough. */
483 if ((match = find_compression_record_match (type, NULL)) > 0)
485 emit_compression_string (match);
489 /* Maybe we already have just JArray somewhere */
490 if ((match = find_compression_array_template_match (atms)) > 0)
491 emit_compression_string (match);
494 /* Start the template mangled name */
495 obstack_grow (mangle_obstack,
496 IDENTIFIER_POINTER (atms), IDENTIFIER_LENGTH (atms));
497 /* Insert in the compression table */
498 compression_table_add (atms);
501 /* Mangle Jarray <elt_type> */
502 obstack_1grow (mangle_obstack, 'I');
503 mangle_type (elt_type);
504 obstack_1grow (mangle_obstack, 'E');
506 /* Add `Jarray <elt_type>' and `Jarray <elt_type> *' to the table */
507 compression_table_add (type);
508 compression_table_add (p_type);
511 /* Write a substition string for entry I. Substitution string starts a
512 -1 (encoded S_.) The base is 36, and the code shamlessly taken from
516 emit_compression_string (int i)
519 obstack_1grow (mangle_obstack, 'S');
522 static const char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
523 unsigned HOST_WIDE_INT n;
524 unsigned HOST_WIDE_INT m=1;
525 /* How many digits for I in base 36? */
526 for (n = i; n >= 36; n /= 36, m *=36);
527 /* Write the digits out */
531 obstack_1grow (mangle_obstack, digits [digit]);
536 obstack_1grow (mangle_obstack, '_');
539 /* If search the compression table at index I for a pointer type
540 equivalent to TYPE (meaning that after all the indirection, which
541 might all be unique, we find the same RECORD_TYPE.) */
544 entry_match_pointer_p (type, i)
548 tree t = TREE_VEC_ELT (compression_table, i);
550 while (TREE_CODE (type) == POINTER_TYPE
551 && TREE_CODE (t) == POINTER_TYPE)
554 type = TREE_TYPE (type);
556 return (TREE_CODE (type) == RECORD_TYPE
557 && TREE_CODE (t) == RECORD_TYPE
561 /* Go through all qualification of type and build a list of list node
562 elements containings as a purpose what should be used for a match and
563 inserted in the compression table; and as it value the raw name of the
564 part. The result is stored in TYPE_PACKAGE_LIST to be reused. */
567 set_type_package_list (type)
571 const char *type_string = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
574 tree list = NULL_TREE, elt;
576 for (ptr = (char *)type_string, qualifications = 0; *ptr; ptr++)
580 for (ptr = (char *)type_string, i = 0; i < qualifications; ptr++)
587 /* Can't use an obstack, we're already using it to
588 accumulate the mangling. */
591 identifier = get_identifier (type_string);
593 elt = build_tree_list (identifier, identifier);
594 TREE_CHAIN (elt) = list;
601 elt = build_tree_list (type, get_identifier (type_string));
602 TREE_CHAIN (elt) = list;
604 TYPE_PACKAGE_LIST (type) = nreverse (list);
607 /* Add TYPE as the last element of the compression table. Resize the
608 compression table if necessary. */
611 compression_table_add (type)
614 if (compression_next == TREE_VEC_LENGTH (compression_table))
616 tree new = make_tree_vec (2*compression_next);
619 for (i = 0; i < compression_next; i++)
620 TREE_VEC_ELT (new, i) = TREE_VEC_ELT (compression_table, i);
622 ggc_del_root (&compression_table);
623 compression_table = new;
624 ggc_add_tree_root (&compression_table, 1);
626 TREE_VEC_ELT (compression_table, compression_next++) = type;
629 /* Mangling initialization routine. */
632 init_mangling (obstack)
633 struct obstack *obstack;
635 mangle_obstack = obstack;
636 if (!compression_table)
637 compression_table = make_tree_vec (10);
639 /* Mangling already in progress. */
642 /* Mangled name are to be suffixed */
643 obstack_grow (mangle_obstack, "_Z", 2);
645 /* Register the compression table with the GC */
646 ggc_add_tree_root (&compression_table, 1);
649 /* Mangling finalization routine. The mangled name is returned as a
657 if (!compression_table)
658 /* Mangling already finished. */
661 ggc_del_root (&compression_table);
662 compression_table = NULL_TREE;
663 compression_next = 0;
664 obstack_1grow (mangle_obstack, '\0');
665 result = get_identifier (obstack_base (mangle_obstack));
666 obstack_free (mangle_obstack, obstack_base (mangle_obstack));
668 printf ("// %s\n", IDENTIFIER_POINTER (result));