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