adabb62874f792e3b2f42c3762f21f365df64cc2
[cacao.git] / src / vm / descriptor.c
1 /* vm/descriptor.c - checking and parsing of field / method descriptors
2
3    Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
4    R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
5    C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
6    Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
23    02111-1307, USA.
24
25    Contact: cacao@complang.tuwien.ac.at
26
27    Authors: Edwin Steiner
28
29    Changes:
30
31    $Id: descriptor.c 2181 2005-04-01 16:53:33Z edwin $
32
33 */
34
35 #include <assert.h>
36
37 #include "vm/descriptor.h"
38 #include "vm/exceptions.h"
39 #include "vm/resolve.h"
40
41
42 /* constants (private to descriptor.c) ****************************************/
43
44 /* initial number of entries for the classrefhash of a descriptor_pool */
45 /* (currently the hash is never grown!) */
46 #define CLASSREFHASH_INIT_SIZE  64
47
48 /* initial number of entries for the descriptorhash of a descriptor_pool */
49 /* (currently the hash is never grown!) */
50 #define DESCRIPTORHASH_INIT_SIZE  128
51
52 /* data structures (private to descriptor.c) **********************************/ 
53
54 typedef struct classref_hash_entry classref_hash_entry;
55 typedef struct descriptor_hash_entry descriptor_hash_entry;
56
57 /* entry struct for the classrefhash of descriptor_pool */
58 struct classref_hash_entry {
59         classref_hash_entry *hashlink;  /* for hash chaining            */
60         utf                 *name;      /* name of the class refered to */
61         u2                   index;     /* index into classref table    */
62 };
63
64 /* entry struct for the descriptorhash of descriptor_pool */
65 struct descriptor_hash_entry {
66         descriptor_hash_entry *hashlink;
67         utf                   *desc;
68         parseddesc             parseddesc;
69 };
70
71 /****************************************************************************/
72 /* DEBUG HELPERS                                                            */
73 /****************************************************************************/
74
75 #ifndef NDEBUG
76 #define DESCRIPTOR_DEBUG
77 #endif
78
79 #ifdef DESCRIPTOR_DEBUG
80 #define DESCRIPTOR_ASSERT(cond)  assert(cond)
81 #else
82 #define DESCRIPTOR_ASSERT(cond)
83 #endif
84
85 /* name_from_descriptor ********************************************************
86
87    Return the class name indicated by the given descriptor
88    (Internally used helper function)
89
90    IN:
91        c................class containing the descriptor
92        utf_ptr..........first character of descriptor
93        end_ptr..........first character after the end of the string
94        mode.............a combination (binary or) of the following flags:
95
96                (Flags marked with * are the default settings.)
97
98                How to handle "V" descriptors:
99
100                              * DESCRIPTOR_VOID.....handle it like other primitive types
101                    DESCRIPTOR_NOVOID...treat it as an error
102
103                How to deal with extra characters after the end of the
104                descriptor:
105
106                              * DESCRIPTOR_NOCHECKEND...ignore (useful for parameter lists)
107                    DESCRIPTOR_CHECKEND.....treat them as an error
108
109    OUT:
110        *next............if non-NULL, *next is set to the first character after
111                         the descriptor. (Undefined if an error occurs.)
112        *name............set to the utf name of the class
113
114    RETURN VALUE:
115        true.............descriptor parsed successfully
116            false............an exception has been thrown
117
118 *******************************************************************************/
119
120 #define DESCRIPTOR_VOID          0      /* default */
121 #define DESCRIPTOR_NOVOID        0x0040
122 #define DESCRIPTOR_NOCHECKEND    0      /* default */
123 #define DESCRIPTOR_CHECKEND      0x1000
124
125 static bool 
126 name_from_descriptor(classinfo *c,
127                                          char *utf_ptr, char *end_ptr,
128                                          char **next, int mode, utf **name)
129 {
130         char *start = utf_ptr;
131         bool error = false;
132
133         DESCRIPTOR_ASSERT(c);
134         DESCRIPTOR_ASSERT(utf_ptr);
135         DESCRIPTOR_ASSERT(end_ptr);
136         DESCRIPTOR_ASSERT(name);
137         
138         *name = NULL;           
139         SKIP_FIELDDESCRIPTOR_SAFE(utf_ptr, end_ptr, error);
140
141         if (mode & DESCRIPTOR_CHECKEND)
142                 error |= (utf_ptr != end_ptr);
143         
144         if (!error) {
145                 if (next) *next = utf_ptr;
146                 
147                 switch (*start) {
148                   case 'V':
149                           if (mode & DESCRIPTOR_NOVOID)
150                                   break;
151                           /* FALLTHROUGH! */
152                   case 'I':
153                   case 'J':
154                   case 'F':
155                   case 'D':
156                   case 'B':
157                   case 'C':
158                   case 'S':
159                   case 'Z':
160                           return true;
161                           
162                   case 'L':
163                           start++;
164                           utf_ptr--;
165                           /* FALLTHROUGH! */
166                   case '[':
167                           *name = utf_new(start, utf_ptr - start);
168                           return true;
169                 }
170         }
171
172         *exceptionptr = new_classformaterror(c,"invalid descriptor");
173         return false;
174 }
175
176 /* primitive_type_from_char ****************************************************
177  
178    Return the primitive type corresponding to the given descriptor character
179    (Internally used helper function)
180
181    IN:
182        ch...............the character
183
184    RETURN VALUE:
185        The primitive type (a TYPE_* constant)
186
187    NOTE:
188        This function assumes that the descriptor has already been checked.
189
190 *******************************************************************************/
191
192 static int
193 primitive_type_from_char(int ch)
194 {
195         switch (ch) {
196                 case 'B': 
197                 case 'C':
198                 case 'I':
199                 case 'S':  
200                 case 'Z':
201                         return TYPE_INT;
202                 case 'D':
203                         return TYPE_DOUBLE;
204                 case 'F':
205                         return TYPE_FLOAT;
206                 case 'J':
207                         return TYPE_LONG;
208                 case 'V':
209                         return TYPE_VOID;
210         }
211         DESCRIPTOR_ASSERT(false);
212         return 0; /* for the compiler */
213 }
214                                 
215 /* descriptor_to_typedesc ******************************************************
216  
217    Parse the given type descriptor and fill a typedesc struct
218    (Internally used helper function)
219
220    IN:
221        pool.............the descriptor pool
222            utf_ptr..........points to first character of type descriptor
223            end_pos..........points after last character of the whole descriptor
224
225    OUT:
226        *next............set to next character after type descriptor
227            *d...............filled with parsed information
228
229    RETURN VALUE:
230        true.............parsing succeeded  
231            false............an exception has been thrown
232
233 *******************************************************************************/
234
235 static bool
236 descriptor_to_typedesc(descriptor_pool *pool,char *utf_ptr,char *end_pos,
237                                            char **next,typedesc *d)
238 {
239         utf *name;
240         
241         if (!name_from_descriptor(pool->referer,utf_ptr,end_pos,next,0,&name))
242                 return false;
243
244         if (name) {
245                 /* a reference type */
246                 d->type = TYPE_ADDRESS;
247                 d->arraydim = 0;
248                 for (utf_ptr=name->text; *utf_ptr == '['; ++utf_ptr)
249                         d->arraydim++;
250                 d->classref = descriptor_pool_lookup_classref(pool,name);
251         }
252         else {
253                 DESCRIPTOR_ASSERT(utf_ptr[0] != '[' && utf_ptr[0] != 'L');
254                 /* a primitive type */
255                 d->type = primitive_type_from_char(*utf_ptr);
256                 d->arraydim = 0;
257                 d->classref = NULL;
258         }
259
260         return true;
261 }
262
263 /* descriptor_pool_new *********************************************************
264  
265    Allocate a new descriptor_pool
266
267    IN:
268        referer..........class for which to create the pool
269
270    RETURN VALUE:
271        a pointer to the new descriptor_pool
272
273 *******************************************************************************/
274
275 descriptor_pool * 
276 descriptor_pool_new(classinfo *referer)
277 {
278         descriptor_pool *pool;
279         u4 hashsize;
280         u4 slot;
281
282         pool = DNEW(descriptor_pool);
283         DESCRIPTOR_ASSERT(pool);
284
285         pool->referer = referer;
286         pool->fieldcount = 0;
287         pool->methodcount = 0;
288         pool->paramcount = 0;
289         pool->descriptorsize = 0;
290         pool->descriptors = NULL;
291         pool->descriptors_next = NULL;
292         pool->classrefs = NULL;
293         pool->descriptor_kind = NULL;
294         pool->descriptor_kind_next = NULL;
295
296         hashsize = CLASSREFHASH_INIT_SIZE;
297         pool->classrefhash.size = hashsize;
298         pool->classrefhash.entries = 0;
299         pool->classrefhash.ptr = DMNEW(voidptr,hashsize);
300         for (slot=0; slot<hashsize; ++slot)
301                 pool->classrefhash.ptr[slot] = NULL;
302
303         hashsize = DESCRIPTORHASH_INIT_SIZE;
304         pool->descriptorhash.size = hashsize;
305         pool->descriptorhash.entries = 0;
306         pool->descriptorhash.ptr = DMNEW(voidptr,hashsize);
307         for (slot=0; slot<hashsize; ++slot)
308                 pool->descriptorhash.ptr[slot] = NULL;
309
310         return pool;
311 }
312
313 /* descriptor_pool_add_class ***************************************************
314  
315    Add the given class reference to the pool
316
317    IN:
318        pool.............the descriptor_pool
319            name.............the class reference to add
320
321    RETURN VALUE:
322        true.............reference has been added
323            false............an exception has been thrown
324
325 *******************************************************************************/
326
327 bool 
328 descriptor_pool_add_class(descriptor_pool *pool,utf *name)
329 {
330         u4 key,slot;
331         classref_hash_entry *c;
332         
333         DESCRIPTOR_ASSERT(pool);
334         DESCRIPTOR_ASSERT(name);
335
336         /* find a place in the hashtable */
337         key = utf_hashkey(name->text, name->blength);
338         slot = key & (pool->classrefhash.size - 1);
339         c = (classref_hash_entry *) pool->classrefhash.ptr[slot];
340         while (c) {
341                 if (c->name == name)
342                         return true; /* already stored */
343                 c = c->hashlink;
344         }
345
346         /* check if the name is a valid classname */
347         if (!is_valid_name(name->text,utf_end(name))) {
348                 *exceptionptr = new_classformaterror(pool->referer,"Invalid class name");
349                 return false; /* exception */
350         }
351
352         /* XXX check maximum array dimension */
353         
354         c = DNEW(classref_hash_entry);
355         c->name = name;
356         c->index = pool->classrefhash.entries++;
357         c->hashlink = (classref_hash_entry *) pool->classrefhash.ptr[slot];
358         pool->classrefhash.ptr[slot] = c;
359
360         return true;
361 }
362
363 /* descriptor_pool_add *********************************************************
364  
365    Check the given descriptor and add it to the pool
366
367    IN:
368        pool.............the descriptor_pool
369            desc.............the descriptor to add. Maybe a field or method desc.
370
371    RETURN VALUE:
372        true.............descriptor has been added
373            false............an exception has been thrown
374
375 *******************************************************************************/
376
377 bool 
378 descriptor_pool_add(descriptor_pool *pool,utf *desc)
379 {
380         u4 key,slot;
381         descriptor_hash_entry *c;
382         char *utf_ptr;
383         char *end_pos;
384         utf *name;
385         
386         DESCRIPTOR_ASSERT(pool);
387         DESCRIPTOR_ASSERT(desc);
388
389         /* find a place in the hashtable */
390         key = utf_hashkey(desc->text, desc->blength);
391         slot = key & (pool->descriptorhash.size - 1);
392         c = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
393         while (c) {
394                 if (c->desc == desc)
395                         return true; /* already stored */
396                 c = c->hashlink;
397         }
398         /* add the descriptor to the pool */
399         c = DNEW(descriptor_hash_entry);
400         c->desc = desc;
401         c->parseddesc.any = NULL;
402         c->hashlink = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
403         pool->descriptorhash.ptr[slot] = c;
404
405         /* now check the descriptor */
406         utf_ptr = desc->text;
407         end_pos = utf_end(desc);
408         
409         if (*utf_ptr == '(') {
410                 s4 argcount = 0;
411                 
412                 /* a method descriptor */
413                 pool->methodcount++;
414                 utf_ptr++;
415
416                 /* check arguments */
417                 while (utf_ptr != end_pos && *utf_ptr != ')') {
418                         pool->paramcount++;
419                         /* We cannot count the this argument here because
420                          * we don't know if the method is static. */
421                         if (*utf_ptr == 'J' || *utf_ptr == 'D')
422                                 argcount+=2;
423                         else
424                                 argcount++;
425                         if (!name_from_descriptor(pool->referer,utf_ptr,end_pos,&utf_ptr,
426                                                                       DESCRIPTOR_NOVOID,&name))
427                                 return false;
428
429                         if (name)
430                                 descriptor_pool_add_class(pool,name);
431                 }
432
433                 if (utf_ptr == end_pos) {
434                         *exceptionptr = new_classformaterror(pool->referer,"Missing ')' in method descriptor");
435                         return false;
436                 }
437
438                 utf_ptr++; /* skip ')' */
439
440                 if (!name_from_descriptor(pool->referer,utf_ptr,end_pos,NULL,
441                                                                   DESCRIPTOR_CHECKEND,&name))
442                         return false;
443
444                 if (name)
445                         descriptor_pool_add_class(pool,name);
446
447                 if (argcount > 255) {
448                         *exceptionptr =
449                                 new_classformaterror(pool->referer,"Too many arguments in signature");
450                         return false;
451                 }
452         }
453         else {
454                 /* a field descriptor */
455                 pool->fieldcount++;
456                 
457             if (!name_from_descriptor(pool->referer,utf_ptr,end_pos,NULL,
458                                                           DESCRIPTOR_NOVOID
459                                                                 | DESCRIPTOR_CHECKEND,&name))
460                         return false;
461
462                 if (name)
463                         descriptor_pool_add_class(pool,name);
464         }
465
466         return true;
467 }
468
469 /* descriptor_pool_create_classrefs ********************************************
470  
471    Create a table containing all the classrefs which were added to the pool
472
473    IN:
474        pool.............the descriptor_pool
475
476    OUT:
477        *count...........if count is non-NULL, this is set to the number
478                             of classrefs in the table
479
480    RETURN VALUE:
481        a pointer to the constant_classref table
482
483 *******************************************************************************/
484
485 constant_classref * 
486 descriptor_pool_create_classrefs(descriptor_pool *pool,s4 *count)
487 {
488         u4 nclasses;
489         u4 slot;
490         classref_hash_entry *c;
491         constant_classref *ref;
492         
493         DESCRIPTOR_ASSERT(pool);
494
495         nclasses = pool->classrefhash.entries;
496         pool->classrefs = MNEW(constant_classref,nclasses);
497
498         /* fill the constant_classref structs */
499         for (slot=0; slot<pool->classrefhash.size; ++slot) {
500                 c = (classref_hash_entry *) pool->classrefhash.ptr[slot];
501                 while (c) {
502                         ref = pool->classrefs + c->index;
503                         CLASSREF_INIT(*ref,pool->referer,c->name);
504                         c = c->hashlink;
505                 }
506         }
507
508         if (count)
509                 *count = nclasses;
510         return pool->classrefs;
511 }
512
513 /* descriptor_pool_lookup_classref *********************************************
514  
515    Return the constant_classref for the given class name
516
517    IN:
518        pool.............the descriptor_pool
519            classname........name of the class to look up
520
521    RETURN VALUE:
522        a pointer to the constant_classref, or
523            NULL if an exception has been thrown
524
525 *******************************************************************************/
526
527 constant_classref * 
528 descriptor_pool_lookup_classref(descriptor_pool *pool,utf *classname)
529 {
530         u4 key,slot;
531         classref_hash_entry *c;
532
533         DESCRIPTOR_ASSERT(pool);
534         DESCRIPTOR_ASSERT(pool->classrefs);
535         DESCRIPTOR_ASSERT(classname);
536
537         key = utf_hashkey(classname->text, classname->blength);
538         slot = key & (pool->classrefhash.size - 1);
539         c = (classref_hash_entry *) pool->classrefhash.ptr[slot];
540         while (c) {
541                 if (c->name == classname)
542                         return pool->classrefs + c->index;
543                 c = c->hashlink;
544         }
545
546         *exceptionptr = new_exception_message(string_java_lang_InternalError,
547                                                                                   "Class reference not found in descriptor pool");
548         return NULL;
549 }
550
551 /* descriptor_pool_alloc_parsed_descriptors ************************************
552  
553    Allocate space for the parsed descriptors
554
555    IN:
556        pool.............the descriptor_pool
557
558    NOTE:
559        This function must be called after all descriptors have been added
560            with descriptor_pool_add.
561
562 *******************************************************************************/
563
564 void 
565 descriptor_pool_alloc_parsed_descriptors(descriptor_pool *pool)
566 {
567         u4 size;
568         
569         DESCRIPTOR_ASSERT(pool);
570
571         size = pool->fieldcount * sizeof(typedesc)
572                  + pool->methodcount * (sizeof(methoddesc) - sizeof(typedesc))
573                  + pool->paramcount * sizeof(typedesc);
574
575         pool->descriptorsize = size;
576         if (size) {
577                 pool->descriptors = MNEW(u1,size);
578                 pool->descriptors_next = pool->descriptors;
579         }
580
581         size = pool->fieldcount + pool->methodcount;
582         if (size) {
583                 pool->descriptor_kind = DMNEW(u1,size);
584                 pool->descriptor_kind_next = pool->descriptor_kind;
585         }
586 }
587
588 /* descriptor_pool_parse_field_descriptor **************************************
589  
590    Parse the given field descriptor
591
592    IN:
593        pool.............the descriptor_pool
594            desc.............the field descriptor
595
596    RETURN VALUE:
597        a pointer to the parsed field descriptor, or
598            NULL if an exception has been thrown
599
600    NOTE:
601        descriptor_pool_alloc_parsed_descriptors must be called (once) before this
602            function is used.
603
604 *******************************************************************************/
605
606 typedesc * 
607 descriptor_pool_parse_field_descriptor(descriptor_pool *pool,utf *desc)
608 {
609         u4 key,slot;
610         descriptor_hash_entry *c;
611         typedesc *d;
612
613         DESCRIPTOR_ASSERT(pool);
614         DESCRIPTOR_ASSERT(pool->descriptors);
615         DESCRIPTOR_ASSERT(pool->descriptors_next);
616
617         /* lookup the descriptor in the hashtable */
618         key = utf_hashkey(desc->text, desc->blength);
619         slot = key & (pool->descriptorhash.size - 1);
620         c = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
621         while (c) {
622                 if (c->desc == desc) {
623                         /* found */
624                         if (c->parseddesc.fd)
625                                 return c->parseddesc.fd;
626                         break;
627                 }
628                 c = c->hashlink;
629         }
630
631         DESCRIPTOR_ASSERT(c);
632         
633         if (desc->text[0] == '(') {
634                 *exceptionptr = new_classformaterror(pool->referer,
635                                 "Method descriptor used in field reference");
636                 return NULL;
637         }
638
639         d = (typedesc *) pool->descriptors_next;
640         pool->descriptors_next += sizeof(typedesc);
641         
642         if (!descriptor_to_typedesc(pool,desc->text,utf_end(desc),NULL,d))
643                 return NULL;
644
645         *(pool->descriptor_kind_next++) = 'f';
646
647         c->parseddesc.fd = d;
648         return d;
649 }
650
651 /* descriptor_pool_parse_method_descriptor *************************************
652  
653    Parse the given method descriptor
654
655    IN:
656        pool.............the descriptor_pool
657            desc.............the method descriptor
658
659    RETURN VALUE:
660        a pointer to the parsed method descriptor, or
661            NULL if an exception has been thrown
662
663    NOTE:
664        descriptor_pool_alloc_parsed_descriptors must be called (once) before this
665            function is used.
666
667 *******************************************************************************/
668
669 methoddesc * 
670 descriptor_pool_parse_method_descriptor(descriptor_pool *pool,utf *desc)
671 {
672         u4 key,slot;
673         descriptor_hash_entry *c;
674         typedesc *d;
675         methoddesc *md;
676         char *utf_ptr;
677         char *end_pos;
678         s2 paramcount = 0;
679         s2 paramslots = 0;
680
681         DESCRIPTOR_ASSERT(pool);
682         DESCRIPTOR_ASSERT(pool->descriptors);
683         DESCRIPTOR_ASSERT(pool->descriptors_next);
684
685         /* lookup the descriptor in the hashtable */
686         key = utf_hashkey(desc->text, desc->blength);
687         slot = key & (pool->descriptorhash.size - 1);
688         c = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
689         while (c) {
690                 if (c->desc == desc) {
691                         /* found */
692                         if (c->parseddesc.md)
693                                 return c->parseddesc.md;
694                         break;
695                 }
696                 c = c->hashlink;
697         }
698
699         DESCRIPTOR_ASSERT(c);
700         
701         md = (methoddesc *) pool->descriptors_next;
702         pool->descriptors_next += sizeof(methoddesc) - sizeof(typedesc);
703
704         utf_ptr = desc->text;
705         end_pos = utf_end(desc);
706
707         if (*utf_ptr++ != '(') {
708                 *exceptionptr = new_classformaterror(pool->referer,
709                                 "Field descriptor used in method reference");
710                 return NULL;
711         }
712
713         d = md->paramtypes;
714         while (*utf_ptr != ')') {
715                 /* parse a parameter type */
716                 if (!descriptor_to_typedesc(pool,utf_ptr,end_pos,&utf_ptr,d))
717                         return NULL;
718
719                 if (d->type == TYPE_LONG || d->type == TYPE_DOUBLE)
720                         paramslots++;
721                 
722                 d++;
723                 pool->descriptors_next += sizeof(typedesc);
724                 paramcount++;
725                 paramslots++;
726         }
727         utf_ptr++; /* skip ')' */
728         
729         /* parse return type */
730         if (!descriptor_to_typedesc(pool,utf_ptr,end_pos,NULL,&(md->returntype)))
731                         return NULL;
732
733         md->paramcount = paramcount;
734         md->paramslots = paramslots;
735         *(pool->descriptor_kind_next++) = 'm';
736         c->parseddesc.md = md;
737         return md;
738 }
739
740 /* descriptor_pool_get_parsed_descriptors **************************************
741  
742    Return a pointer to the block of parsed descriptors
743
744    IN:
745        pool.............the descriptor_pool
746
747    OUT:
748            *size............if size is non-NULL, this is set to the size of the
749                             parsed descriptor block (in u1)
750
751    RETURN VALUE:
752        a pointer to the block of parsed descriptors
753
754    NOTE:
755        descriptor_pool_alloc_parsed_descriptors must be called (once) before this
756            function is used.
757
758 *******************************************************************************/
759
760 void * 
761 descriptor_pool_get_parsed_descriptors(descriptor_pool *pool,s4 *size)
762 {
763         DESCRIPTOR_ASSERT(pool);
764         DESCRIPTOR_ASSERT((!pool->fieldcount && !pool->methodcount) || pool->descriptors);
765         
766         if (size)
767                 *size = pool->descriptorsize;
768         return pool->descriptors;
769 }
770
771 /* descriptor_pool_get_sizes ***************************************************
772  
773    Get the sizes of the class reference table and the parsed descriptors
774
775    IN:
776        pool.............the descriptor_pool
777
778    OUT:
779        *classrefsize....set to size of the class reference table
780            *descsize........set to size of the parsed descriptors
781
782    NOTE:
783        This function may only be called after both
784                descriptor_pool_create_classrefs, and
785                    descriptor_pool_alloc_parsed_descriptors
786            have been called.
787
788 *******************************************************************************/
789
790 void 
791 descriptor_pool_get_sizes(descriptor_pool *pool,
792                                               u4 *classrefsize,u4 *descsize)
793 {
794         DESCRIPTOR_ASSERT(pool);
795         DESCRIPTOR_ASSERT((!pool->fieldcount && !pool->methodcount) || pool->descriptors);
796         DESCRIPTOR_ASSERT(pool->classrefs);
797         DESCRIPTOR_ASSERT(classrefsize);
798         DESCRIPTOR_ASSERT(descsize);
799
800         *classrefsize = pool->classrefhash.entries * sizeof(constant_classref);
801         *descsize = pool->descriptorsize;
802 }
803
804 /* descriptor_debug_print_typedesc *********************************************
805  
806    Print the given typedesc to the given stream
807
808    IN:
809            file.............stream to print to
810            d................the parsed descriptor
811
812 *******************************************************************************/
813
814 void 
815 descriptor_debug_print_typedesc(FILE *file,typedesc *d)
816 {
817         int ch;
818
819         if (!d) {
820                 fprintf(file,"(typedesc *)NULL");
821                 return;
822         }
823         
824         if (d->type == TYPE_ADDRESS) {
825                 utf_fprint(file,d->classref->name);
826         }
827         else {
828                 switch (d->type) {
829                         case TYPE_INT    : ch='I'; break;
830                         case TYPE_LONG   : ch='J'; break;
831                         case TYPE_FLOAT  : ch='F'; break;
832                         case TYPE_DOUBLE : ch='D'; break;
833                         case TYPE_ADDRESS: ch='A'; break;
834                         case TYPE_VOID   : ch='V'; break;
835                         default          : ch='!';
836                 }
837                 fputc(ch,file);
838         }
839         if (d->arraydim)
840                 fprintf(file,"[%d]",d->arraydim);
841 }
842
843 /* descriptor_debug_print_methoddesc *******************************************
844  
845    Print the given methoddesc to the given stream
846
847    IN:
848            file.............stream to print to
849            d................the parsed descriptor
850
851 *******************************************************************************/
852
853 void 
854 descriptor_debug_print_methoddesc(FILE *file,methoddesc *d)
855 {
856         int i;
857         
858         if (!d) {
859                 fprintf(file,"(methoddesc *)NULL");
860                 return;
861         }
862         
863         fputc('(',file);
864         for (i=0; i<d->paramcount; ++i) {
865                 if (i)
866                         fputc(',',file);
867                 descriptor_debug_print_typedesc(file,d->paramtypes + i);
868         }
869         fputc(')',file);
870         descriptor_debug_print_typedesc(file,&(d->returntype));
871 }
872
873 /* descriptor_pool_debug_dump **************************************************
874  
875    Print the state of the descriptor_pool to the given stream
876
877    IN:
878        pool.............the descriptor_pool
879            file.............stream to print to
880
881 *******************************************************************************/
882
883 void 
884 descriptor_pool_debug_dump(descriptor_pool *pool,FILE *file)
885 {
886         u4 slot;
887         u1 *pos;
888         u1 *kind;
889         u4 size;
890         
891         fprintf(file,"======[descriptor_pool for ");
892         utf_fprint(file,pool->referer->name);
893         fprintf(file,"]======\n");
894
895         fprintf(file,"fieldcount:     %d\n",pool->fieldcount);
896         fprintf(file,"methodcount:    %d\n",pool->methodcount);
897         fprintf(file,"paramcount:     %d\n",pool->paramcount);
898         fprintf(file,"classrefcount:  %d\n",pool->classrefhash.entries);
899         fprintf(file,"descriptorsize: %d bytes\n",pool->descriptorsize);
900         fprintf(file,"classrefsize:   %d bytes\n",
901                         pool->classrefhash.entries * sizeof(constant_classref));
902
903         fprintf(file,"class references:\n");
904         for (slot=0; slot<pool->classrefhash.size; ++slot) {
905                 classref_hash_entry *c = (classref_hash_entry *) pool->classrefhash.ptr[slot];
906                 while (c) {
907                         fprintf(file,"    %4d: ",c->index);
908                         utf_fprint(file,c->name);
909                         fprintf(file,"\n");
910                         c = c->hashlink;
911                 }
912         }
913
914         fprintf(file,"hashed descriptors:\n");
915         for (slot=0; slot<pool->descriptorhash.size; ++slot) {
916                 descriptor_hash_entry *c = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
917                 while (c) {
918                         fprintf(file,"    %p: ",c->parseddesc.any);
919                         utf_fprint(file,c->desc);
920                         fprintf(file,"\n");
921                         c = c->hashlink;
922                 }
923         }
924
925         fprintf(file,"descriptors:\n");
926         if (pool->descriptors) {
927                 pos = pool->descriptors;
928                 size = pool->descriptors_next - pool->descriptors;
929                 fprintf(file,"    size: %d bytes\n",size);
930                 
931                 if (pool->descriptor_kind) {
932                         kind = pool->descriptor_kind;
933
934                         while (pos < (pool->descriptors + size)) {
935                                 fprintf(file,"    %p: ",pos);
936                                 switch (*kind++) {
937                                         case 'f':
938                                                 descriptor_debug_print_typedesc(file,(typedesc*)pos);
939                                                 pos += sizeof(typedesc);
940                                                 break;
941                                         case 'm':
942                                                 descriptor_debug_print_methoddesc(file,(methoddesc*)pos);
943                                                 pos += ((methoddesc*)pos)->paramcount * sizeof(typedesc);
944                                                 pos += sizeof(methoddesc) - sizeof(typedesc);
945                                                 break;
946                                         default:
947                                                 fprintf(file,"INVALID KIND");
948                                 }
949                                 fputc('\n',file);
950                         }
951                 }
952                 else {
953                         while (size >= sizeof(voidptr)) {
954                                 fprintf(file,"    %p\n",*((voidptr*)pos));
955                                 pos += sizeof(voidptr);
956                                 size -= sizeof(voidptr);
957                         }
958                 }
959         }
960
961         fprintf(file,"==========================================================\n");
962 }
963
964 /*
965  * These are local overrides for various environment variables in Emacs.
966  * Please do not remove this and leave it at the end of the file, where
967  * Emacs will automagically detect them.
968  * ---------------------------------------------------------------------
969  * Local variables:
970  * mode: c
971  * indent-tabs-mode: t
972  * c-basic-offset: 4
973  * tab-width: 4
974  * End:
975  * vim:noexpandtab:sw=4:ts=4:
976  */
977