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