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