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