fa34c60aced72d5c4c4f8d6836cb72ac32f6f9d2
[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 3380 2005-10-06 13:48:16Z 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                 pool->fieldcount++;
552                 
553             if (!name_from_descriptor(pool->referer, utf_ptr, end_pos, NULL,
554                                                           DESCRIPTOR_NOVOID | DESCRIPTOR_CHECKEND,
555                                                                   &name))
556                         return false;
557
558                 if (name)
559                         if (!descriptor_pool_add_class(pool,name))
560                                 return false;
561         }
562
563         d->paramslots = argcount;
564
565         if (paramslots)
566                 *paramslots = argcount;
567
568         return true;
569 }
570
571
572 /* descriptor_pool_create_classrefs ********************************************
573  
574    Create a table containing all the classrefs which were added to the pool
575
576    IN:
577        pool.............the descriptor_pool
578
579    OUT:
580        *count...........if count is non-NULL, this is set to the number
581                             of classrefs in the table
582
583    RETURN VALUE:
584        a pointer to the constant_classref table
585
586 *******************************************************************************/
587
588 constant_classref * 
589 descriptor_pool_create_classrefs(descriptor_pool *pool, s4 *count)
590 {
591         u4 nclasses;
592         u4 slot;
593         classref_hash_entry *c;
594         constant_classref *ref;
595         
596         DESCRIPTOR_ASSERT(pool);
597
598         nclasses = pool->classrefhash.entries;
599         pool->classrefs = MNEW(constant_classref,nclasses);
600
601         /* fill the constant_classref structs */
602
603         for (slot = 0; slot < pool->classrefhash.size; ++slot) {
604                 c = (classref_hash_entry *) pool->classrefhash.ptr[slot];
605                 while (c) {
606                         ref = pool->classrefs + c->index;
607                         CLASSREF_INIT(*ref, pool->referer, c->name);
608                         c = c->hashlink;
609                 }
610         }
611
612         if (count)
613                 *count = nclasses;
614
615         return pool->classrefs;
616 }
617
618
619 /* descriptor_pool_lookup_classref *********************************************
620  
621    Return the constant_classref for the given class name
622
623    IN:
624        pool.............the descriptor_pool
625            classname........name of the class to look up
626
627    RETURN VALUE:
628        a pointer to the constant_classref, or
629            NULL if an exception has been thrown
630
631 *******************************************************************************/
632
633 constant_classref * 
634 descriptor_pool_lookup_classref(descriptor_pool *pool, utf *classname)
635 {
636         u4 key,slot;
637         classref_hash_entry *c;
638
639         DESCRIPTOR_ASSERT(pool);
640         DESCRIPTOR_ASSERT(pool->classrefs);
641         DESCRIPTOR_ASSERT(classname);
642
643         key = utf_hashkey(classname->text, classname->blength);
644         slot = key & (pool->classrefhash.size - 1);
645         c = (classref_hash_entry *) pool->classrefhash.ptr[slot];
646
647         while (c) {
648                 if (c->name == classname)
649                         return pool->classrefs + c->index;
650                 c = c->hashlink;
651         }
652
653         *exceptionptr = new_internalerror("Class reference not found in descriptor pool");
654         return NULL;
655 }
656
657
658 /* descriptor_pool_alloc_parsed_descriptors ************************************
659  
660    Allocate space for the parsed descriptors
661
662    IN:
663        pool.............the descriptor_pool
664
665    NOTE:
666        This function must be called after all descriptors have been added
667            with descriptor_pool_add.
668
669 *******************************************************************************/
670
671 void 
672 descriptor_pool_alloc_parsed_descriptors(descriptor_pool *pool)
673 {
674         u4 size;
675         
676         DESCRIPTOR_ASSERT(pool);
677
678         /* TWISTI: paramcount + 1: we don't know if the method is static or   */
679         /* not, i have no better solution yet.                                */
680
681         size =
682                 pool->fieldcount * sizeof(typedesc) +
683                 pool->methodcount * (sizeof(methoddesc) - sizeof(typedesc)) +
684                 pool->paramcount * sizeof(typedesc) +
685                 pool->methodcount * sizeof(typedesc);      /* possible `this' pointer */
686
687         pool->descriptorsize = size;
688         if (size) {
689                 pool->descriptors = MNEW(u1, size);
690                 pool->descriptors_next = pool->descriptors;
691         }
692
693         size = pool->fieldcount + pool->methodcount;
694         if (size) {
695                 pool->descriptor_kind = DMNEW(u1, size);
696                 pool->descriptor_kind_next = pool->descriptor_kind;
697         }
698 }
699
700
701 /* descriptor_pool_parse_field_descriptor **************************************
702  
703    Parse the given field descriptor
704
705    IN:
706        pool.............the descriptor_pool
707            desc.............the field descriptor
708
709    RETURN VALUE:
710        a pointer to the parsed field descriptor, or
711            NULL if an exception has been thrown
712
713    NOTE:
714        descriptor_pool_alloc_parsed_descriptors must be called (once)
715        before this function is used.
716
717 *******************************************************************************/
718
719 typedesc * 
720 descriptor_pool_parse_field_descriptor(descriptor_pool *pool, utf *desc)
721 {
722         u4 key,slot;
723         descriptor_hash_entry *d;
724         typedesc *td;
725
726         DESCRIPTOR_ASSERT(pool);
727         DESCRIPTOR_ASSERT(pool->descriptors);
728         DESCRIPTOR_ASSERT(pool->descriptors_next);
729
730         /* lookup the descriptor in the hashtable */
731
732         key = utf_hashkey(desc->text, desc->blength);
733         slot = key & (pool->descriptorhash.size - 1);
734         d = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
735
736         while (d) {
737                 if (d->desc == desc) {
738                         /* found */
739                         if (d->parseddesc.fd)
740                                 return d->parseddesc.fd;
741                         break;
742                 }
743                 d = d->hashlink;
744         }
745
746         DESCRIPTOR_ASSERT(d);
747         
748         if (desc->text[0] == '(') {
749                 *exceptionptr = new_classformaterror(pool->referer,
750                                 "Method descriptor used in field reference");
751                 return NULL;
752         }
753
754         td = (typedesc *) pool->descriptors_next;
755         pool->descriptors_next += sizeof(typedesc);
756         
757         if (!descriptor_to_typedesc(pool, desc->text, UTF_END(desc), NULL, td))
758                 return NULL;
759
760         *(pool->descriptor_kind_next++) = 'f';
761
762         d->parseddesc.fd = td;
763
764         return td;
765 }
766
767
768 /* descriptor_pool_parse_method_descriptor *************************************
769  
770    Parse the given method descriptor
771
772    IN:
773        pool.............the descriptor_pool
774        desc.............the method descriptor
775        mflags...........the method flags
776            thisclass........classref to the class containing the method.
777                                                 This is ignored if mflags contains ACC_STATIC.
778                                                 The classref is stored for inserting the 'this' argument.
779
780    RETURN VALUE:
781        a pointer to the parsed method descriptor, or
782            NULL if an exception has been thrown
783
784    NOTE: 
785        descriptor_pool_alloc_parsed_descriptors must be called
786        (once) before this function is used.
787
788 *******************************************************************************/
789
790 methoddesc * 
791 descriptor_pool_parse_method_descriptor(descriptor_pool *pool, utf *desc,
792                                                                                 s4 mflags,constant_classref *thisclass)
793 {
794         u4 key, slot;
795         descriptor_hash_entry *d;
796         methoddesc            *md;
797         typedesc              *td;
798         char *utf_ptr;
799         char *end_pos;
800         s2 paramcount = 0;
801         s2 paramslots = 0;
802
803 #ifdef DESCRIPTOR_VERBOSE
804         fprintf(stderr,"descriptor_pool_parse_method_descriptor(%p,%d,%p,",
805                         (void*)pool,(int)mflags,(void*)thisclass);
806         utf_fprint(stderr,desc); fprintf(stderr,")\n");
807 #endif
808
809         DESCRIPTOR_ASSERT(pool);
810         DESCRIPTOR_ASSERT(pool->descriptors);
811         DESCRIPTOR_ASSERT(pool->descriptors_next);
812
813         /* lookup the descriptor in the hashtable */
814
815         key = utf_hashkey(desc->text, desc->blength);
816         slot = key & (pool->descriptorhash.size - 1);
817         d = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
818
819         /* find an un-parsed descriptor */
820
821         while (d) {
822                 if (d->desc == desc)
823                         if (!d->parseddesc.md)
824                                 break;
825                 d = d->hashlink;
826         }
827
828         DESCRIPTOR_ASSERT(d);
829
830         md = (methoddesc *) pool->descriptors_next;
831         pool->descriptors_next += sizeof(methoddesc) - sizeof(typedesc);
832
833         utf_ptr = desc->text;
834         end_pos = UTF_END(desc);
835
836         if (*utf_ptr++ != '(') {
837                 *exceptionptr = new_classformaterror(pool->referer,
838                                 "Field descriptor used in method reference");
839                 return NULL;
840         }
841
842         td = md->paramtypes;
843
844         /* count the `this' pointer */
845
846         if ((mflags != ACC_UNDEF) && !(mflags & ACC_STATIC)) {
847                 td->type = TYPE_ADR;
848                 td->decltype = TYPE_ADR;
849                 td->arraydim = 0;
850                 td->classref = thisclass;
851
852                 td++;
853                 pool->descriptors_next += sizeof(typedesc);
854                 paramcount++;
855                 paramslots++;
856         }
857
858         while (*utf_ptr != ')') {
859                 /* parse a parameter type */
860
861                 if (!descriptor_to_typedesc(pool, utf_ptr, end_pos, &utf_ptr, td))
862                         return NULL;
863
864                 if (td->type == TYPE_LONG || td->type == TYPE_DOUBLE)
865                         paramslots++;
866                 
867                 td++;
868                 pool->descriptors_next += sizeof(typedesc);
869                 paramcount++;
870                 paramslots++;
871         }
872         utf_ptr++; /* skip ')' */
873
874         /* Skip possible `this' pointer in paramtypes array to allow a possible   */
875         /* memory move later in parse.                                            */
876         /* We store the thisclass reference, so we can later correctly fill in    */
877         /* the parameter slot of the 'this' argument.                             */
878
879         if (mflags == ACC_UNDEF) {
880                 td->classref = thisclass;
881                 td++;
882                 pool->descriptors_next += sizeof(typedesc);
883         }
884
885         /* parse return type */
886
887         if (!descriptor_to_typedesc(pool, utf_ptr, end_pos, NULL,
888                                                                 &(md->returntype)))
889                 return NULL;
890
891         md->paramcount = paramcount;
892         md->paramslots = paramslots;
893
894         /* If m != ACC_UNDEF we parse a real loaded method, so do param prealloc. */
895         /* Otherwise we do this in stack analysis.                                */
896
897         if (mflags != ACC_UNDEF) {
898                 if (md->paramcount > 0) {
899                         /* allocate memory for params */
900
901                         md->params = MNEW(paramdesc, md->paramcount);
902                 }
903                 else {
904                         md->params = METHODDESC_NOPARAMS;
905                 }
906
907                 /* fill the paramdesc */
908                 /* md_param_alloc has to be called if md->paramcount == 0, too, so it */
909                 /* can make the reservation for the Linkage Area, Return Register...  */
910                 md_param_alloc(md);
911         }
912         else {
913                 /* params will be allocated later by descriptor_params_from_paramtypes */
914                 /* if necessary                                                        */
915                 md->params = NULL;
916         }
917
918         *(pool->descriptor_kind_next++) = 'm';
919
920         d->parseddesc.md = md;
921
922         return md;
923 }
924
925 /* descriptor_params_from_paramtypes *******************************************
926  
927    Create the paramdescs for a method descriptor. This function is called
928    when we know whether the method is static or not. This function may only
929    be called once for each methoddesc, and only if md->params == NULL.
930
931    IN:
932        md...............the parsed method descriptor
933                             md->params MUST be NULL.
934            mflags...........the ACC_* access flags of the method. Only the
935                             ACC_STATIC bit is checked.
936                                                 The value ACC_UNDEF is NOT allowed.
937
938    RETURN VALUE:
939        true.............the paramdescs were created successfully
940            false............an exception has been thrown
941
942    POSTCONDITION:
943        md->parms != NULL
944
945 *******************************************************************************/
946
947 bool descriptor_params_from_paramtypes(methoddesc *md, s4 mflags)
948 {
949         typedesc *td;
950
951         DESCRIPTOR_ASSERT(md);
952         DESCRIPTOR_ASSERT(md->params == NULL);
953         DESCRIPTOR_ASSERT(mflags != ACC_UNDEF);
954
955         td = md->paramtypes;
956
957         /* check for `this' pointer */
958
959         if (!(mflags & ACC_STATIC)) {
960                 constant_classref *thisclass;
961
962                 /* fetch class reference from reserved param slot */
963                 thisclass = td[md->paramcount].classref;
964                 DESCRIPTOR_ASSERT(thisclass);
965
966                 if (md->paramcount > 0) {
967                         /* shift param types by 1 argument */
968                         MMOVE(td + 1, td, typedesc, md->paramcount);
969                 }
970
971                 /* fill in first argument `this' */
972
973                 td->type = TYPE_ADR;
974                 td->decltype = TYPE_ADR;
975                 td->arraydim = 0;
976                 td->classref = thisclass;
977
978                 md->paramcount++;
979                 md->paramslots++;
980         }
981
982         /* if the method has params, process them */
983
984         if (md->paramcount > 0) {
985                 /* allocate memory for params */
986
987                 md->params = MNEW(paramdesc, md->paramcount);
988         }
989         else {
990                 md->params = METHODDESC_NOPARAMS;
991         }
992
993         /* fill the paramdesc */
994         /* md_param_alloc has to be called if md->paramcount == 0, too, so     */
995         /* it can make the reservation for the Linkage Area, Return Register.. */
996
997         md_param_alloc(md);
998
999         return true;
1000 }
1001
1002
1003 /* descriptor_pool_get_parsed_descriptors **************************************
1004  
1005    Return a pointer to the block of parsed descriptors
1006
1007    IN:
1008        pool.............the descriptor_pool
1009
1010    OUT:
1011            *size............if size is non-NULL, this is set to the size of the
1012                             parsed descriptor block (in u1)
1013
1014    RETURN VALUE:
1015        a pointer to the block of parsed descriptors
1016
1017    NOTE:
1018        descriptor_pool_alloc_parsed_descriptors must be called (once)
1019        before this function is used.
1020
1021 *******************************************************************************/
1022
1023 void * 
1024 descriptor_pool_get_parsed_descriptors(descriptor_pool *pool, s4 *size)
1025 {
1026         DESCRIPTOR_ASSERT(pool);
1027         DESCRIPTOR_ASSERT((!pool->fieldcount && !pool->methodcount) || pool->descriptors);
1028         
1029         if (size)
1030                 *size = pool->descriptorsize;
1031
1032         return pool->descriptors;
1033 }
1034
1035
1036 /* descriptor_pool_get_sizes ***************************************************
1037  
1038    Get the sizes of the class reference table and the parsed descriptors
1039
1040    IN:
1041        pool.............the descriptor_pool
1042
1043    OUT:
1044        *classrefsize....set to size of the class reference table
1045            *descsize........set to size of the parsed descriptors
1046
1047    NOTE:
1048        This function may only be called after both
1049                descriptor_pool_create_classrefs, and
1050                    descriptor_pool_alloc_parsed_descriptors
1051            have been called.
1052
1053 *******************************************************************************/
1054
1055 void 
1056 descriptor_pool_get_sizes(descriptor_pool *pool, u4 *classrefsize, u4 *descsize)
1057 {
1058         DESCRIPTOR_ASSERT(pool);
1059         DESCRIPTOR_ASSERT((!pool->fieldcount && !pool->methodcount) || pool->descriptors);
1060         DESCRIPTOR_ASSERT(pool->classrefs);
1061         DESCRIPTOR_ASSERT(classrefsize);
1062         DESCRIPTOR_ASSERT(descsize);
1063
1064         *classrefsize = pool->classrefhash.entries * sizeof(constant_classref);
1065         *descsize = pool->descriptorsize;
1066 }
1067
1068
1069 /* descriptor_debug_print_typedesc *********************************************
1070  
1071    Print the given typedesc to the given stream
1072
1073    IN:
1074            file.............stream to print to
1075            d................the parsed descriptor
1076
1077 *******************************************************************************/
1078
1079 void 
1080 descriptor_debug_print_typedesc(FILE *file,typedesc *d)
1081 {
1082         int ch;
1083
1084         if (!d) {
1085                 fprintf(file,"(typedesc *)NULL");
1086                 return;
1087         }
1088         
1089         if (d->type == TYPE_ADDRESS) {
1090                 if (d->classref)
1091                         utf_fprint(file,d->classref->name);
1092                 else
1093                         fprintf(file,"<class=NULL>");
1094         }
1095         else {
1096                 switch (d->decltype) {
1097                         case PRIMITIVETYPE_INT    : ch='I'; break;
1098                         case PRIMITIVETYPE_CHAR   : ch='C'; break;
1099                         case PRIMITIVETYPE_BYTE   : ch='B'; break;
1100                         case PRIMITIVETYPE_SHORT  : ch='S'; break;
1101                         case PRIMITIVETYPE_BOOLEAN: ch='Z'; break;
1102                         case PRIMITIVETYPE_LONG   : ch='J'; break;
1103                         case PRIMITIVETYPE_FLOAT  : ch='F'; break;
1104                         case PRIMITIVETYPE_DOUBLE : ch='D'; break;
1105                         case PRIMITIVETYPE_VOID   : ch='V'; break;
1106                         default                   : ch='!';
1107                 }
1108                 fputc(ch,file);
1109         }
1110         if (d->arraydim)
1111                 fprintf(file,"[%d]",d->arraydim);
1112 }
1113
1114 /* descriptor_debug_print_paramdesc ********************************************
1115  
1116    Print the given paramdesc to the given stream
1117
1118    IN:
1119            file.............stream to print to
1120            d................the parameter descriptor
1121
1122 *******************************************************************************/
1123
1124 void
1125 descriptor_debug_print_paramdesc(FILE *file,paramdesc *d)
1126 {
1127         if (!d) {
1128                 fprintf(file,"(paramdesc *)NULL");
1129                 return;
1130         }
1131         
1132         if (d->inmemory) {
1133                 fprintf(file,"<m%d>",d->regoff);
1134         }
1135         else {
1136                 fprintf(file,"<r%d>",d->regoff);
1137         }
1138 }
1139
1140 /* descriptor_debug_print_methoddesc *******************************************
1141  
1142    Print the given methoddesc to the given stream
1143
1144    IN:
1145            file.............stream to print to
1146            d................the parsed descriptor
1147
1148 *******************************************************************************/
1149
1150 void 
1151 descriptor_debug_print_methoddesc(FILE *file,methoddesc *d)
1152 {
1153         int i;
1154         
1155         if (!d) {
1156                 fprintf(file,"(methoddesc *)NULL");
1157                 return;
1158         }
1159         
1160         fputc('(',file);
1161         for (i=0; i<d->paramcount; ++i) {
1162                 if (i)
1163                         fputc(',',file);
1164                 descriptor_debug_print_typedesc(file,d->paramtypes + i);
1165                 if (d->params) {
1166                         descriptor_debug_print_paramdesc(file,d->params + i);
1167                 }
1168         }
1169         if (d->params == METHODDESC_NOPARAMS)
1170                 fputs("<NOPARAMS>",file);
1171         fputc(')',file);
1172         descriptor_debug_print_typedesc(file,&(d->returntype));
1173 }
1174
1175 /* descriptor_pool_debug_dump **************************************************
1176  
1177    Print the state of the descriptor_pool to the given stream
1178
1179    IN:
1180        pool.............the descriptor_pool
1181            file.............stream to print to
1182
1183 *******************************************************************************/
1184
1185 void 
1186 descriptor_pool_debug_dump(descriptor_pool *pool,FILE *file)
1187 {
1188         u4 slot;
1189         u1 *pos;
1190         u1 *kind;
1191         u4 size;
1192         
1193         fprintf(file,"======[descriptor_pool for ");
1194         utf_fprint(file,pool->referer->name);
1195         fprintf(file,"]======\n");
1196
1197         fprintf(file,"fieldcount:     %d\n",pool->fieldcount);
1198         fprintf(file,"methodcount:    %d\n",pool->methodcount);
1199         fprintf(file,"paramcount:     %d\n",pool->paramcount);
1200         fprintf(file,"classrefcount:  %d\n",pool->classrefhash.entries);
1201         fprintf(file,"descriptorsize: %d bytes\n",pool->descriptorsize);
1202         fprintf(file,"classrefsize:   %d bytes\n",
1203                         (int)(pool->classrefhash.entries * sizeof(constant_classref)));
1204
1205         fprintf(file,"class references:\n");
1206         for (slot=0; slot<pool->classrefhash.size; ++slot) {
1207                 classref_hash_entry *c = (classref_hash_entry *) pool->classrefhash.ptr[slot];
1208                 while (c) {
1209                         fprintf(file,"    %4d: ",c->index);
1210                         utf_fprint(file,c->name);
1211                         fprintf(file,"\n");
1212                         c = c->hashlink;
1213                 }
1214         }
1215
1216         fprintf(file,"hashed descriptors:\n");
1217         for (slot=0; slot<pool->descriptorhash.size; ++slot) {
1218                 descriptor_hash_entry *c = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
1219                 while (c) {
1220                         fprintf(file,"    %p: ",c->parseddesc.any);
1221                         utf_fprint(file,c->desc);
1222                         fprintf(file,"\n");
1223                         c = c->hashlink;
1224                 }
1225         }
1226
1227         fprintf(file,"descriptors:\n");
1228         if (pool->descriptors) {
1229                 pos = pool->descriptors;
1230                 size = pool->descriptors_next - pool->descriptors;
1231                 fprintf(file,"    size: %d bytes\n",size);
1232                 
1233                 if (pool->descriptor_kind) {
1234                         kind = pool->descriptor_kind;
1235
1236                         while (pos < (pool->descriptors + size)) {
1237                                 fprintf(file,"    %p: ",pos);
1238                                 switch (*kind++) {
1239                                         case 'f':
1240                                                 descriptor_debug_print_typedesc(file,(typedesc*)pos);
1241                                                 pos += sizeof(typedesc);
1242                                                 break;
1243                                         case 'm':
1244                                                 descriptor_debug_print_methoddesc(file,(methoddesc*)pos);
1245                                                 pos += ((methoddesc*)pos)->paramcount * sizeof(typedesc);
1246                                                 pos += sizeof(methoddesc) - sizeof(typedesc);
1247                                                 break;
1248                                         default:
1249                                                 fprintf(file,"INVALID KIND");
1250                                 }
1251                                 fputc('\n',file);
1252                         }
1253                 }
1254                 else {
1255                         while (size >= sizeof(voidptr)) {
1256                                 fprintf(file,"    %p\n",*((voidptr*)pos));
1257                                 pos += sizeof(voidptr);
1258                                 size -= sizeof(voidptr);
1259                         }
1260                 }
1261         }
1262
1263         fprintf(file,"==========================================================\n");
1264 }
1265
1266 /*
1267  * These are local overrides for various environment variables in Emacs.
1268  * Please do not remove this and leave it at the end of the file, where
1269  * Emacs will automagically detect them.
1270  * ---------------------------------------------------------------------
1271  * Local variables:
1272  * mode: c
1273  * indent-tabs-mode: t
1274  * c-basic-offset: 4
1275  * tab-width: 4
1276  * End:
1277  * vim:noexpandtab:sw=4:ts=4:
1278  */
1279