OSDN Git Service

* mangle.c (find_compression_record_match): Don't match compression
[pf3gnuchains/gcc-fork.git] / gcc / java / mangle.c
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
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 
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
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
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
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 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))
153     {
154       if (DECL_CONTEXT (mdecl) == object_type_node)
155         obstack_grow (mangle_obstack, "C2", 2);
156       else
157         obstack_grow (mangle_obstack, "C1", 2);
158     }
159   else
160     mangle_member_name (method_name);
161   obstack_1grow (mangle_obstack, 'E');
162
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);
167   
168   /* No arguments is easy. We shortcut it. */
169   if (arglist == end_params_node)
170     obstack_1grow (mangle_obstack, 'v');
171   else
172     {
173       tree arg;
174       for (arg = arglist; arg != end_params_node;  arg = TREE_CHAIN (arg))
175         mangle_type (TREE_VALUE (arg));
176     }
177 }
178
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.  */
182
183 static void
184 mangle_member_name (name)
185      tree name;
186 {
187   append_gpp_mangled_name (IDENTIFIER_POINTER (name),
188                            IDENTIFIER_LENGTH (name));
189
190   /* If NAME happens to be a C++ keyword, add `$' or `.' or `_'. */
191   if (cxx_keyword_p (IDENTIFIER_POINTER (name), IDENTIFIER_LENGTH (name)))
192     {
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 */
202     }
203 }
204
205 /* Append the mangled name of TYPE onto OBSTACK.  */
206
207 static void
208 mangle_type (type)
209      tree type;
210 {
211   switch (TREE_CODE (type))
212     {
213       char code;
214     case BOOLEAN_TYPE: code = 'b';  goto primitive;
215     case CHAR_TYPE:    code = 'w';  goto primitive;
216     case VOID_TYPE:    code = 'v';  goto primitive;
217     case INTEGER_TYPE:
218       /* Get the original type instead of the arguments promoted type.
219          Avoid symbol name clashes. Should call a function to do that.
220          FIXME.  */
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))
226         {
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;
232         }
233     primitive:
234       obstack_1grow (mangle_obstack, code);
235       break;
236
237     case REAL_TYPE:
238       switch (TYPE_PRECISION (type))
239         {
240         case 32:       code = 'f';  goto primitive;
241         case 64:       code = 'd';  goto primitive;
242         default:  goto bad_type;
243         }
244     case POINTER_TYPE:
245       if (TYPE_ARRAY_P (TREE_TYPE (type)))
246         mangle_array_type (type);
247       else
248         mangle_pointer_type (type);
249       break;
250     bad_type:
251     default:
252       abort ();
253     }
254 }
255
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
263    of an element.  */
264
265 static tree compression_table;
266 static int  compression_next;
267
268 /* Find a POINTER_TYPE in the compression table. Use a special
269    function to match pointer entries and start from the end */
270
271 static int
272 find_compression_pointer_match (type)
273      tree type;
274 {
275   int i;
276
277   for (i = compression_next-1; i >= 0; i--)
278     if (entry_match_pointer_p (type, i))
279       return i;
280   return -1;
281 }
282
283 /* Already recorder arrays are handled like pointer as they're always
284    associated with it.  */
285
286 static int
287 find_compression_array_match (type)
288      tree type;
289 {
290   return find_compression_pointer_match (type);
291 }
292
293 /* Match the table of type against STRING.  */
294
295 static int
296 find_compression_array_template_match (string)
297      tree string;
298 {
299   int i;
300   for (i = 0; i < compression_next; i++)
301     if (TREE_VEC_ELT (compression_table, i) == string) 
302       return i;
303   return -1;
304 }
305
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. */
310
311 static int
312 find_compression_record_match (type, next_current)
313      tree type;
314      tree *next_current;
315 {
316   int i, match;
317   tree current, saved_current = NULL_TREE;
318
319   /* Search from the beginning for something that matches TYPE, even
320      partially. */
321   for (current = TYPE_PACKAGE_LIST (type), i = 0, match = -1; current;
322        current = TREE_CHAIN (current))
323     {
324       int j;
325       for (j = i; j < compression_next; j++)
326         if (TREE_VEC_ELT (compression_table, j) == TREE_PURPOSE (current))
327           {
328             match = i = j;
329             saved_current = current;
330             i++;
331             break;
332           }
333         else
334           {
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)) == 
341                       IDENTIFIER_NODE)
342               j++;
343           }
344     }
345
346   if (!next_current)
347     return match;
348
349   /* If we have a match, set next_current to the item next to the last
350      matched value. */
351   if (match >= 0)
352     *next_current = TREE_CHAIN (saved_current);
353   /* We had no match: we'll have to start from the beginning. */
354   if (match < 0)
355     *next_current = TYPE_PACKAGE_LIST (type);
356
357   return match;
358 }
359
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'. */
364
365 static int
366 mangle_record_type (type, for_pointer)
367      tree type;
368      int for_pointer;
369 {
370   tree current;
371   int match;
372   int nadded_p = 0;
373   int qualified;
374   
375   /* Does this name have a package qualifier? */
376   qualified = QUALIFIED_P (DECL_NAME (TYPE_NAME (type)));
377
378 #define ADD_N() \
379   do { obstack_1grow (mangle_obstack, 'N'); nadded_p = 1; } while (0)
380
381   if (TREE_CODE (type) != RECORD_TYPE)
382     abort ();
383
384   if (!TYPE_PACKAGE_LIST (type))
385     set_type_package_list (type);
386
387   match = find_compression_record_match (type, &current);
388   if (match >= 0)
389     {
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)
393         ADD_N();
394       emit_compression_string (match);
395     }
396   while (current)
397     {
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)
403         ADD_N();
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);
408     }
409   return nadded_p;
410 #undef ADD_N
411 }
412
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. */
417
418 static void
419 mangle_pointer_type (type)
420      tree type;
421 {
422   int match;
423   tree pointer_type;
424
425   /* Search for the type already in the compression table */
426   if ((match = find_compression_pointer_match (type)) >= 0) 
427     {
428       emit_compression_string (match);
429       return;
430     }
431   
432   /* This didn't work. We start by mangling the pointed-to type */
433   pointer_type = type;
434   type = TREE_TYPE (type);
435   if (TREE_CODE (type) != RECORD_TYPE)
436     abort ();
437   
438   obstack_1grow (mangle_obstack, 'P');
439   if (mangle_record_type (type, /* for_pointer = */ 1))
440     obstack_1grow (mangle_obstack, 'E');
441
442   /* Don't forget to insert the pointer type in the table */
443   compression_table_add (pointer_type);
444 }
445
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. */
450
451 static void
452 mangle_array_type (p_type)
453      tree p_type;
454 {
455   /* atms: array template mangled string. */
456   static tree atms = NULL_TREE;
457   tree type, elt_type;
458   int match;
459
460   type = TREE_TYPE (p_type);
461   if (!type)
462     abort ();
463
464   elt_type = TYPE_ARRAY_ELEMENT (type);
465
466   /* We cache a bit of the Jarray <> mangle. */
467   if (!atms)
468     {
469       atms = get_identifier ("6JArray");
470       ggc_add_tree_root (&atms, 1);
471     }
472
473   /* Maybe we have what we're looking in the compression table. */
474   if ((match = find_compression_array_match (p_type)) >= 0)
475     {
476       emit_compression_string (match);
477       return;
478     }
479
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)
484     {
485       emit_compression_string (match);
486       return;
487     }
488
489   /* Maybe we already have just JArray somewhere */
490   if ((match = find_compression_array_template_match (atms)) > 0)
491     emit_compression_string (match);
492   else
493     {
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);
499     } 
500
501   /* Mangle Jarray <elt_type> */
502   obstack_1grow (mangle_obstack, 'I');
503   mangle_type (elt_type);
504   obstack_1grow (mangle_obstack, 'E');
505
506   /* Add `Jarray <elt_type>' and `Jarray <elt_type> *' to the table */
507   compression_table_add (type);
508   compression_table_add (p_type);
509 }
510
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
513    cp/mangle.c.  */
514
515 static void
516 emit_compression_string (int i)
517 {
518   i -= 1;                       /* Adjust */
519   obstack_1grow (mangle_obstack, 'S');
520   if (i >= 0)
521     {
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 */
528       while (m > 0)
529         {
530           int digit = i / m;
531           obstack_1grow (mangle_obstack, digits [digit]);
532           i -= digit * m;
533           m /= 36;
534         }
535     }
536   obstack_1grow (mangle_obstack, '_');
537 }
538
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.) */
542
543 static int
544 entry_match_pointer_p (type, i)
545      tree type;
546      int i;
547 {
548   tree t = TREE_VEC_ELT (compression_table, i);
549   
550   while (TREE_CODE (type) == POINTER_TYPE
551          && TREE_CODE (t) == POINTER_TYPE)
552     {
553       t = TREE_TYPE (t);
554       type = TREE_TYPE (type);
555     }
556   return (TREE_CODE (type) == RECORD_TYPE
557           && TREE_CODE (t) == RECORD_TYPE
558           && t == type);
559 }
560
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.  */
565
566 static void
567 set_type_package_list (type)
568      tree type;
569 {
570   int i;
571   const char *type_string = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
572   char *ptr;
573   int qualifications;
574   tree list = NULL_TREE, elt;
575
576   for (ptr = (char *)type_string, qualifications = 0; *ptr; ptr++)
577     if (*ptr == '.')
578       qualifications += 1;
579
580   for (ptr = (char *)type_string, i = 0; i < qualifications; ptr++)
581     {
582       if (ptr [0] == '.')
583         {
584           char c;
585           tree identifier;
586
587           /* Can't use an obstack, we're already using it to
588              accumulate the mangling. */
589           c = ptr [0];
590           ptr [0] = '\0';
591           identifier = get_identifier (type_string);
592           ptr [0] = c;
593           elt = build_tree_list (identifier, identifier);
594           TREE_CHAIN (elt) = list;
595           list = elt;
596           type_string = ptr+1;
597           i += 1;
598         }
599     }
600
601   elt = build_tree_list (type, get_identifier (type_string));
602   TREE_CHAIN (elt) = list;
603   list = elt;
604   TYPE_PACKAGE_LIST (type) = nreverse (list);
605 }
606
607 /* Add TYPE as the last element of the compression table. Resize the
608    compression table if necessary.  */
609
610 static void
611 compression_table_add (type)
612      tree type;
613 {
614   if (compression_next == TREE_VEC_LENGTH (compression_table))
615     {
616       tree new = make_tree_vec (2*compression_next);
617       int i;
618
619       for (i = 0; i < compression_next; i++)
620         TREE_VEC_ELT (new, i) = TREE_VEC_ELT (compression_table, i);
621
622       ggc_del_root (&compression_table);
623       compression_table = new;
624       ggc_add_tree_root (&compression_table, 1);
625     }
626   TREE_VEC_ELT (compression_table, compression_next++) = type;
627 }
628
629 /* Mangling initialization routine.  */
630
631 static void
632 init_mangling (obstack)
633      struct obstack *obstack;
634 {
635   mangle_obstack = obstack;
636   if (!compression_table)
637     compression_table = make_tree_vec (10);
638   else
639     /* Mangling already in progress.  */
640     abort ();
641
642   /* Mangled name are to be suffixed */
643   obstack_grow (mangle_obstack, "_Z", 2);
644
645   /* Register the compression table with the GC */
646   ggc_add_tree_root (&compression_table, 1);
647 }
648
649 /* Mangling finalization routine. The mangled name is returned as a
650    IDENTIFIER_NODE.  */
651
652 static tree
653 finish_mangling ()
654 {
655   tree result;
656
657   if (!compression_table)
658     /* Mangling already finished.  */
659     abort ();
660
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));
667 #if 0
668   printf ("// %s\n", IDENTIFIER_POINTER (result));
669 #endif
670   return result;
671 }