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