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.
4
5 This file is part of GNU CC.
6
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)
10 any later version.
11
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.
16
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.
21
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. */
25
26 /* Written by Per Bothner <bothner@cygnus.com> */
27
28 #include "config.h"
29 #include "system.h"
30 #include "jcf.h"
31 #include "tree.h"
32 #include "java-tree.h"
33 #include "obstack.h"
34 #include "toplev.h"
35 #include "obstack.h"
36 #include "ggc.h"
37
38 static void mangle_field_decl PARAMS ((tree));
39 static void mangle_method_decl PARAMS ((tree));
40
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));
45
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));
50
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));
54
55 static void init_mangling PARAMS ((struct obstack *));
56 static tree finish_mangling PARAMS ((void));
57 static void compression_table_add PARAMS ((tree));
58
59 static void mangle_member_name PARAMS ((tree));
60
61 /* We use an incoming obstack, always to be provided to the interface
62 functions. */
63 struct obstack *mangle_obstack;
64 #define MANGLE_RAW_STRING(S) \
65 obstack_grow (mangle_obstack, (S), sizeof (S)-1)
66
67 /* This is the mangling interface: a decl, a class field (.class) and
68 the vtable. */
69
70 tree
java_mangle_decl(obstack,decl)71 java_mangle_decl (obstack, decl)
72 struct obstack *obstack;
73 tree decl;
74 {
75 init_mangling (obstack);
76 switch (TREE_CODE (decl))
77 {
78 case VAR_DECL:
79 mangle_field_decl (decl);
80 break;
81 case FUNCTION_DECL:
82 mangle_method_decl (decl);
83 break;
84 default:
85 internal_error ("can't mangle %s", tree_code_name [TREE_CODE (decl)]);
86 }
87 return finish_mangling ();
88 }
89
90 tree
java_mangle_class_field(obstack,type)91 java_mangle_class_field (obstack, type)
92 struct obstack *obstack;
93 tree type;
94 {
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 ();
100 }
101
102 tree
java_mangle_vtable(obstack,type)103 java_mangle_vtable (obstack, type)
104 struct obstack *obstack;
105 tree type;
106 {
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 ();
112 }
113
114 /* Beginning of the helper functions */
115
116 /* This mangles a field decl */
117
118 static void
mangle_field_decl(decl)119 mangle_field_decl (decl)
120 tree decl;
121 {
122 /* Mangle the name of the this the field belongs to */
123 mangle_record_type (DECL_CONTEXT (decl), /* for_pointer = */ 0);
124
125 /* Mangle the name of the field */
126 mangle_member_name (DECL_NAME (decl));
127
128 /* Terminate the mangled name */
129 obstack_1grow (mangle_obstack, 'E');
130 }
131
132 /* This mangles a method decl, first mangling its name and then all
133 its arguments. */
134
135 static void
mangle_method_decl(mdecl)136 mangle_method_decl (mdecl)
137 tree mdecl;
138 {
139 tree method_name = DECL_NAME (mdecl);
140 tree arglist;
141
142 /* Mangle the name of the type that contains mdecl */
143 mangle_record_type (DECL_CONTEXT (mdecl), /* for_pointer = */ 0);
144
145 /* Mangle the function name. There are two cases:
146 - mdecl is a constructor, use `C1' for its name, (denotes a
147 complete object constructor.)
148 - mdecl is not a constructor, standard mangling is performed.
149 We terminate the mangled function name with a `E'. */
150 if (ID_INIT_P (method_name))
151 obstack_grow (mangle_obstack, "C1", 2);
152 else
153 mangle_member_name (method_name);
154 obstack_1grow (mangle_obstack, 'E');
155
156 /* We mangled type.methodName. Now onto the arguments. */
157 arglist = TYPE_ARG_TYPES (TREE_TYPE (mdecl));
158 if (TREE_CODE (TREE_TYPE (mdecl)) == METHOD_TYPE)
159 arglist = TREE_CHAIN (arglist);
160
161 /* No arguments is easy. We shortcut it. */
162 if (arglist == end_params_node)
163 obstack_1grow (mangle_obstack, 'v');
164 else
165 {
166 tree arg;
167 for (arg = arglist; arg != end_params_node; arg = TREE_CHAIN (arg))
168 mangle_type (TREE_VALUE (arg));
169 }
170 }
171
172 /* This mangles a member name, like a function name or a field
173 name. Handle cases were `name' is a C++ keyword. Return a nonzero
174 value if unicode encoding was required. */
175
176 static void
mangle_member_name(name)177 mangle_member_name (name)
178 tree name;
179 {
180 append_gpp_mangled_name (IDENTIFIER_POINTER (name),
181 IDENTIFIER_LENGTH (name));
182
183 /* If NAME happens to be a C++ keyword, add `$'. */
184 if (cxx_keyword_p (IDENTIFIER_POINTER (name), IDENTIFIER_LENGTH (name)))
185 obstack_1grow (mangle_obstack, '$');
186 }
187
188 /* Append the mangled name of TYPE onto OBSTACK. */
189
190 static void
mangle_type(type)191 mangle_type (type)
192 tree type;
193 {
194 switch (TREE_CODE (type))
195 {
196 char code;
197 case BOOLEAN_TYPE: code = 'b'; goto primitive;
198 case CHAR_TYPE: code = 'w'; goto primitive;
199 case VOID_TYPE: code = 'v'; goto primitive;
200 case INTEGER_TYPE:
201 /* Get the original type instead of the arguments promoted type.
202 Avoid symbol name clashes. Should call a function to do that.
203 FIXME. */
204 if (type == promoted_short_type_node)
205 type = short_type_node;
206 if (type == promoted_byte_type_node)
207 type = byte_type_node;
208 switch (TYPE_PRECISION (type))
209 {
210 case 8: code = 'c'; goto primitive;
211 case 16: code = 's'; goto primitive;
212 case 32: code = 'i'; goto primitive;
213 case 64: code = 'x'; goto primitive;
214 default: goto bad_type;
215 }
216 primitive:
217 obstack_1grow (mangle_obstack, code);
218 break;
219
220 case REAL_TYPE:
221 switch (TYPE_PRECISION (type))
222 {
223 case 32: code = 'f'; goto primitive;
224 case 64: code = 'd'; goto primitive;
225 default: goto bad_type;
226 }
227 case POINTER_TYPE:
228 if (TYPE_ARRAY_P (TREE_TYPE (type)))
229 mangle_array_type (type);
230 else
231 mangle_pointer_type (type);
232 break;
233 bad_type:
234 default:
235 abort ();
236 }
237 }
238
239 /* The compression table is a vector that keeps track of things we've
240 already seen, so they can be reused. For example, java.lang.Object
241 would generate three entries: two package names and a type. If
242 java.lang.String is presented next, the java.lang will be matched
243 against the first two entries (and kept for compression as S_0), and
244 type String would be added to the table. See mangle_record_type.
245 COMPRESSION_NEXT is the index to the location of the next insertion
246 of an element. */
247
248 static GTY(()) tree compression_table;
249 static int compression_next;
250
251 /* Find a POINTER_TYPE in the compression table. Use a special
252 function to match pointer entries and start from the end */
253
254 static int
find_compression_pointer_match(type)255 find_compression_pointer_match (type)
256 tree type;
257 {
258 int i;
259
260 for (i = compression_next-1; i >= 0; i--)
261 if (entry_match_pointer_p (type, i))
262 return i;
263 return -1;
264 }
265
266 /* Already recorder arrays are handled like pointer as they're always
267 associated with it. */
268
269 static int
find_compression_array_match(type)270 find_compression_array_match (type)
271 tree type;
272 {
273 return find_compression_pointer_match (type);
274 }
275
276 /* Match the table of type against STRING. */
277
278 static int
find_compression_array_template_match(string)279 find_compression_array_template_match (string)
280 tree string;
281 {
282 int i;
283 for (i = 0; i < compression_next; i++)
284 if (TREE_VEC_ELT (compression_table, i) == string)
285 return i;
286 return -1;
287 }
288
289 /* We go through the compression table and try to find a complete or
290 partial match. The function returns the compression table entry
291 that (evenutally partially) matches TYPE. *NEXT_CURRENT can be set
292 to the rest of TYPE to be mangled. */
293
294 static int
find_compression_record_match(type,next_current)295 find_compression_record_match (type, next_current)
296 tree type;
297 tree *next_current;
298 {
299 int i, match;
300 tree current, saved_current = NULL_TREE;
301
302 /* Search from the beginning for something that matches TYPE, even
303 partially. */
304 for (current = TYPE_PACKAGE_LIST (type), i = 0, match = -1; current;
305 current = TREE_CHAIN (current))
306 {
307 int j;
308 for (j = i; j < compression_next; j++)
309 if (TREE_VEC_ELT (compression_table, j) == TREE_PURPOSE (current))
310 {
311 match = i = j;
312 saved_current = current;
313 i++;
314 break;
315 }
316 else
317 {
318 /* We don't want to match an element that appears in the middle
319 of a package name, so skip forward to the next complete type name.
320 IDENTIFIER_NODEs are partial package names while RECORD_TYPEs
321 represent complete type names. */
322 while (j < compression_next
323 && TREE_CODE (TREE_VEC_ELT (compression_table, j)) ==
324 IDENTIFIER_NODE)
325 j++;
326 }
327 }
328
329 if (!next_current)
330 return match;
331
332 /* If we have a match, set next_current to the item next to the last
333 matched value. */
334 if (match >= 0)
335 *next_current = TREE_CHAIN (saved_current);
336 /* We had no match: we'll have to start from the beginning. */
337 if (match < 0)
338 *next_current = TYPE_PACKAGE_LIST (type);
339
340 return match;
341 }
342
343 /* Mangle a record type. If a nonzero value is returned, it means
344 that a 'N' was emitted (so that a matching 'E' can be emitted if
345 necessary.) FOR_POINTER indicates that this element is for a pointer
346 symbol, meaning it was preceded by a 'P'. */
347
348 static int
mangle_record_type(type,for_pointer)349 mangle_record_type (type, for_pointer)
350 tree type;
351 int for_pointer;
352 {
353 tree current;
354 int match;
355 int nadded_p = 0;
356 int qualified;
357
358 /* Does this name have a package qualifier? */
359 qualified = QUALIFIED_P (DECL_NAME (TYPE_NAME (type)));
360
361 #define ADD_N() \
362 do { obstack_1grow (mangle_obstack, 'N'); nadded_p = 1; } while (0)
363
364 if (TREE_CODE (type) != RECORD_TYPE)
365 abort ();
366
367 if (!TYPE_PACKAGE_LIST (type))
368 set_type_package_list (type);
369
370 match = find_compression_record_match (type, ¤t);
371 if (match >= 0)
372 {
373 /* If we had a pointer, and there's more, we need to emit
374 'N' after 'P' (for_pointer tells us we already emitted it.) */
375 if (for_pointer && current)
376 ADD_N();
377 emit_compression_string (match);
378 }
379 while (current)
380 {
381 /* Add the new type to the table */
382 compression_table_add (TREE_PURPOSE (current));
383 /* Add 'N' if we never got a chance to, but only if we have a qualified
384 name. For non-pointer elements, the name is always qualified. */
385 if ((qualified || !for_pointer) && !nadded_p)
386 ADD_N();
387 /* Use the bare type name for the mangle. */
388 append_gpp_mangled_name (IDENTIFIER_POINTER (TREE_VALUE (current)),
389 IDENTIFIER_LENGTH (TREE_VALUE (current)));
390 current = TREE_CHAIN (current);
391 }
392 return nadded_p;
393 #undef ADD_N
394 }
395
396 /* Mangle a pointer type. There are two cases: the pointer is already
397 in the compression table: the compression is emited sans 'P'
398 indicator. Otherwise, a 'P' is emitted and, depending on the type,
399 a partial compression or/plus the rest of the mangling. */
400
401 static void
mangle_pointer_type(type)402 mangle_pointer_type (type)
403 tree type;
404 {
405 int match;
406 tree pointer_type;
407
408 /* Search for the type already in the compression table */
409 if ((match = find_compression_pointer_match (type)) >= 0)
410 {
411 emit_compression_string (match);
412 return;
413 }
414
415 /* This didn't work. We start by mangling the pointed-to type */
416 pointer_type = type;
417 type = TREE_TYPE (type);
418 if (TREE_CODE (type) != RECORD_TYPE)
419 abort ();
420
421 obstack_1grow (mangle_obstack, 'P');
422 if (mangle_record_type (type, /* for_pointer = */ 1))
423 obstack_1grow (mangle_obstack, 'E');
424
425 /* Don't forget to insert the pointer type in the table */
426 compression_table_add (pointer_type);
427 }
428
429 /* Mangle an array type. Search for an easy solution first, then go
430 through the process of finding out whether the bare array type or even
431 the template indicator where already used an compress appropriately.
432 It handles pointers. */
433
434 /* atms: array template mangled string. */
435 static GTY(()) tree atms;
436 static void
mangle_array_type(p_type)437 mangle_array_type (p_type)
438 tree p_type;
439 {
440 tree type, elt_type;
441 int match;
442
443 type = TREE_TYPE (p_type);
444 if (!type)
445 abort ();
446
447 elt_type = TYPE_ARRAY_ELEMENT (type);
448
449 /* We cache a bit of the Jarray <> mangle. */
450 if (!atms)
451 {
452 atms = get_identifier ("6JArray");
453 }
454
455 /* Maybe we have what we're looking in the compression table. */
456 if ((match = find_compression_array_match (p_type)) >= 0)
457 {
458 emit_compression_string (match);
459 return;
460 }
461
462 /* We know for a fact that all arrays are pointers */
463 obstack_1grow (mangle_obstack, 'P');
464 /* Maybe we already have a Jarray<t> somewhere. PSx_ will be enough. */
465 if ((match = find_compression_record_match (type, NULL)) > 0)
466 {
467 emit_compression_string (match);
468 return;
469 }
470
471 /* Maybe we already have just JArray somewhere */
472 if ((match = find_compression_array_template_match (atms)) > 0)
473 emit_compression_string (match);
474 else
475 {
476 /* Start the template mangled name */
477 obstack_grow (mangle_obstack,
478 IDENTIFIER_POINTER (atms), IDENTIFIER_LENGTH (atms));
479 /* Insert in the compression table */
480 compression_table_add (atms);
481 }
482
483 /* Mangle Jarray <elt_type> */
484 obstack_1grow (mangle_obstack, 'I');
485 mangle_type (elt_type);
486 obstack_1grow (mangle_obstack, 'E');
487
488 /* Add `Jarray <elt_type>' and `Jarray <elt_type> *' to the table */
489 compression_table_add (type);
490 compression_table_add (p_type);
491 }
492
493 /* Write a substition string for entry I. Substitution string starts a
494 -1 (encoded S_.) The base is 36, and the code shamlessly taken from
495 cp/mangle.c. */
496
497 static void
emit_compression_string(int i)498 emit_compression_string (int i)
499 {
500 i -= 1; /* Adjust */
501 obstack_1grow (mangle_obstack, 'S');
502 if (i >= 0)
503 {
504 static const char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
505 unsigned HOST_WIDE_INT n;
506 unsigned HOST_WIDE_INT m=1;
507 /* How many digits for I in base 36? */
508 for (n = i; n >= 36; n /= 36, m *=36);
509 /* Write the digits out */
510 while (m > 0)
511 {
512 int digit = i / m;
513 obstack_1grow (mangle_obstack, digits [digit]);
514 i -= digit * m;
515 m /= 36;
516 }
517 }
518 obstack_1grow (mangle_obstack, '_');
519 }
520
521 /* If search the compression table at index I for a pointer type
522 equivalent to TYPE (meaning that after all the indirection, which
523 might all be unique, we find the same RECORD_TYPE.) */
524
525 static int
entry_match_pointer_p(type,i)526 entry_match_pointer_p (type, i)
527 tree type;
528 int i;
529 {
530 tree t = TREE_VEC_ELT (compression_table, i);
531
532 while (TREE_CODE (type) == POINTER_TYPE
533 && TREE_CODE (t) == POINTER_TYPE)
534 {
535 t = TREE_TYPE (t);
536 type = TREE_TYPE (type);
537 }
538 return (TREE_CODE (type) == RECORD_TYPE
539 && TREE_CODE (t) == RECORD_TYPE
540 && t == type);
541 }
542
543 /* Go through all qualification of type and build a list of list node
544 elements containings as a purpose what should be used for a match and
545 inserted in the compression table; and as it value the raw name of the
546 part. The result is stored in TYPE_PACKAGE_LIST to be reused. */
547
548 static void
set_type_package_list(type)549 set_type_package_list (type)
550 tree type;
551 {
552 int i;
553 const char *type_string = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
554 char *ptr;
555 int qualifications;
556 tree list = NULL_TREE, elt;
557
558 for (ptr = (char *)type_string, qualifications = 0; *ptr; ptr++)
559 if (*ptr == '.')
560 qualifications += 1;
561
562 for (ptr = (char *)type_string, i = 0; i < qualifications; ptr++)
563 {
564 if (ptr [0] == '.')
565 {
566 char c;
567 tree identifier;
568
569 /* Can't use an obstack, we're already using it to
570 accumulate the mangling. */
571 c = ptr [0];
572 ptr [0] = '\0';
573 identifier = get_identifier (type_string);
574 ptr [0] = c;
575 elt = build_tree_list (identifier, identifier);
576 TREE_CHAIN (elt) = list;
577 list = elt;
578 type_string = ptr+1;
579 i += 1;
580 }
581 }
582
583 elt = build_tree_list (type, get_identifier (type_string));
584 TREE_CHAIN (elt) = list;
585 list = elt;
586 TYPE_PACKAGE_LIST (type) = nreverse (list);
587 }
588
589 /* Add TYPE as the last element of the compression table. Resize the
590 compression table if necessary. */
591
592 static void
compression_table_add(type)593 compression_table_add (type)
594 tree type;
595 {
596 if (compression_next == TREE_VEC_LENGTH (compression_table))
597 {
598 tree new = make_tree_vec (2*compression_next);
599 int i;
600
601 for (i = 0; i < compression_next; i++)
602 TREE_VEC_ELT (new, i) = TREE_VEC_ELT (compression_table, i);
603
604 compression_table = new;
605 }
606 TREE_VEC_ELT (compression_table, compression_next++) = type;
607 }
608
609 /* Mangling initialization routine. */
610
611 static void
init_mangling(obstack)612 init_mangling (obstack)
613 struct obstack *obstack;
614 {
615 mangle_obstack = obstack;
616 if (!compression_table)
617 compression_table = make_tree_vec (10);
618 else
619 /* Mangling already in progress. */
620 abort ();
621
622 /* Mangled name are to be suffixed */
623 obstack_grow (mangle_obstack, "_Z", 2);
624 }
625
626 /* Mangling finalization routine. The mangled name is returned as a
627 IDENTIFIER_NODE. */
628
629 static tree
finish_mangling()630 finish_mangling ()
631 {
632 tree result;
633
634 if (!compression_table)
635 /* Mangling already finished. */
636 abort ();
637
638 compression_table = NULL_TREE;
639 compression_next = 0;
640 obstack_1grow (mangle_obstack, '\0');
641 result = get_identifier (obstack_base (mangle_obstack));
642 obstack_free (mangle_obstack, obstack_base (mangle_obstack));
643 #if 0
644 printf ("// %s\n", IDENTIFIER_POINTER (result));
645 #endif
646 return result;
647 }
648
649 #include "gt-java-mangle.h"
650