1 /* vm/descriptor.c - checking and parsing of field / method descriptors
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
8 This file is part of CACAO.
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.
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.
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
25 Contact: cacao@complang.tuwien.ac.at
27 Authors: Edwin Steiner
31 $Id: descriptor.c 2181 2005-04-01 16:53:33Z edwin $
37 #include "vm/descriptor.h"
38 #include "vm/exceptions.h"
39 #include "vm/resolve.h"
42 /* constants (private to descriptor.c) ****************************************/
44 /* initial number of entries for the classrefhash of a descriptor_pool */
45 /* (currently the hash is never grown!) */
46 #define CLASSREFHASH_INIT_SIZE 64
48 /* initial number of entries for the descriptorhash of a descriptor_pool */
49 /* (currently the hash is never grown!) */
50 #define DESCRIPTORHASH_INIT_SIZE 128
52 /* data structures (private to descriptor.c) **********************************/
54 typedef struct classref_hash_entry classref_hash_entry;
55 typedef struct descriptor_hash_entry descriptor_hash_entry;
57 /* entry struct for the classrefhash of descriptor_pool */
58 struct classref_hash_entry {
59 classref_hash_entry *hashlink; /* for hash chaining */
60 utf *name; /* name of the class refered to */
61 u2 index; /* index into classref table */
64 /* entry struct for the descriptorhash of descriptor_pool */
65 struct descriptor_hash_entry {
66 descriptor_hash_entry *hashlink;
68 parseddesc parseddesc;
71 /****************************************************************************/
73 /****************************************************************************/
76 #define DESCRIPTOR_DEBUG
79 #ifdef DESCRIPTOR_DEBUG
80 #define DESCRIPTOR_ASSERT(cond) assert(cond)
82 #define DESCRIPTOR_ASSERT(cond)
85 /* name_from_descriptor ********************************************************
87 Return the class name indicated by the given descriptor
88 (Internally used helper function)
91 c................class containing the descriptor
92 utf_ptr..........first character of descriptor
93 end_ptr..........first character after the end of the string
94 mode.............a combination (binary or) of the following flags:
96 (Flags marked with * are the default settings.)
98 How to handle "V" descriptors:
100 * DESCRIPTOR_VOID.....handle it like other primitive types
101 DESCRIPTOR_NOVOID...treat it as an error
103 How to deal with extra characters after the end of the
106 * DESCRIPTOR_NOCHECKEND...ignore (useful for parameter lists)
107 DESCRIPTOR_CHECKEND.....treat them as an error
110 *next............if non-NULL, *next is set to the first character after
111 the descriptor. (Undefined if an error occurs.)
112 *name............set to the utf name of the class
115 true.............descriptor parsed successfully
116 false............an exception has been thrown
118 *******************************************************************************/
120 #define DESCRIPTOR_VOID 0 /* default */
121 #define DESCRIPTOR_NOVOID 0x0040
122 #define DESCRIPTOR_NOCHECKEND 0 /* default */
123 #define DESCRIPTOR_CHECKEND 0x1000
126 name_from_descriptor(classinfo *c,
127 char *utf_ptr, char *end_ptr,
128 char **next, int mode, utf **name)
130 char *start = utf_ptr;
133 DESCRIPTOR_ASSERT(c);
134 DESCRIPTOR_ASSERT(utf_ptr);
135 DESCRIPTOR_ASSERT(end_ptr);
136 DESCRIPTOR_ASSERT(name);
139 SKIP_FIELDDESCRIPTOR_SAFE(utf_ptr, end_ptr, error);
141 if (mode & DESCRIPTOR_CHECKEND)
142 error |= (utf_ptr != end_ptr);
145 if (next) *next = utf_ptr;
149 if (mode & DESCRIPTOR_NOVOID)
167 *name = utf_new(start, utf_ptr - start);
172 *exceptionptr = new_classformaterror(c,"invalid descriptor");
176 /* primitive_type_from_char ****************************************************
178 Return the primitive type corresponding to the given descriptor character
179 (Internally used helper function)
182 ch...............the character
185 The primitive type (a TYPE_* constant)
188 This function assumes that the descriptor has already been checked.
190 *******************************************************************************/
193 primitive_type_from_char(int ch)
211 DESCRIPTOR_ASSERT(false);
212 return 0; /* for the compiler */
215 /* descriptor_to_typedesc ******************************************************
217 Parse the given type descriptor and fill a typedesc struct
218 (Internally used helper function)
221 pool.............the descriptor pool
222 utf_ptr..........points to first character of type descriptor
223 end_pos..........points after last character of the whole descriptor
226 *next............set to next character after type descriptor
227 *d...............filled with parsed information
230 true.............parsing succeeded
231 false............an exception has been thrown
233 *******************************************************************************/
236 descriptor_to_typedesc(descriptor_pool *pool,char *utf_ptr,char *end_pos,
237 char **next,typedesc *d)
241 if (!name_from_descriptor(pool->referer,utf_ptr,end_pos,next,0,&name))
245 /* a reference type */
246 d->type = TYPE_ADDRESS;
248 for (utf_ptr=name->text; *utf_ptr == '['; ++utf_ptr)
250 d->classref = descriptor_pool_lookup_classref(pool,name);
253 DESCRIPTOR_ASSERT(utf_ptr[0] != '[' && utf_ptr[0] != 'L');
254 /* a primitive type */
255 d->type = primitive_type_from_char(*utf_ptr);
263 /* descriptor_pool_new *********************************************************
265 Allocate a new descriptor_pool
268 referer..........class for which to create the pool
271 a pointer to the new descriptor_pool
273 *******************************************************************************/
276 descriptor_pool_new(classinfo *referer)
278 descriptor_pool *pool;
282 pool = DNEW(descriptor_pool);
283 DESCRIPTOR_ASSERT(pool);
285 pool->referer = referer;
286 pool->fieldcount = 0;
287 pool->methodcount = 0;
288 pool->paramcount = 0;
289 pool->descriptorsize = 0;
290 pool->descriptors = NULL;
291 pool->descriptors_next = NULL;
292 pool->classrefs = NULL;
293 pool->descriptor_kind = NULL;
294 pool->descriptor_kind_next = NULL;
296 hashsize = CLASSREFHASH_INIT_SIZE;
297 pool->classrefhash.size = hashsize;
298 pool->classrefhash.entries = 0;
299 pool->classrefhash.ptr = DMNEW(voidptr,hashsize);
300 for (slot=0; slot<hashsize; ++slot)
301 pool->classrefhash.ptr[slot] = NULL;
303 hashsize = DESCRIPTORHASH_INIT_SIZE;
304 pool->descriptorhash.size = hashsize;
305 pool->descriptorhash.entries = 0;
306 pool->descriptorhash.ptr = DMNEW(voidptr,hashsize);
307 for (slot=0; slot<hashsize; ++slot)
308 pool->descriptorhash.ptr[slot] = NULL;
313 /* descriptor_pool_add_class ***************************************************
315 Add the given class reference to the pool
318 pool.............the descriptor_pool
319 name.............the class reference to add
322 true.............reference has been added
323 false............an exception has been thrown
325 *******************************************************************************/
328 descriptor_pool_add_class(descriptor_pool *pool,utf *name)
331 classref_hash_entry *c;
333 DESCRIPTOR_ASSERT(pool);
334 DESCRIPTOR_ASSERT(name);
336 /* find a place in the hashtable */
337 key = utf_hashkey(name->text, name->blength);
338 slot = key & (pool->classrefhash.size - 1);
339 c = (classref_hash_entry *) pool->classrefhash.ptr[slot];
342 return true; /* already stored */
346 /* check if the name is a valid classname */
347 if (!is_valid_name(name->text,utf_end(name))) {
348 *exceptionptr = new_classformaterror(pool->referer,"Invalid class name");
349 return false; /* exception */
352 /* XXX check maximum array dimension */
354 c = DNEW(classref_hash_entry);
356 c->index = pool->classrefhash.entries++;
357 c->hashlink = (classref_hash_entry *) pool->classrefhash.ptr[slot];
358 pool->classrefhash.ptr[slot] = c;
363 /* descriptor_pool_add *********************************************************
365 Check the given descriptor and add it to the pool
368 pool.............the descriptor_pool
369 desc.............the descriptor to add. Maybe a field or method desc.
372 true.............descriptor has been added
373 false............an exception has been thrown
375 *******************************************************************************/
378 descriptor_pool_add(descriptor_pool *pool,utf *desc)
381 descriptor_hash_entry *c;
386 DESCRIPTOR_ASSERT(pool);
387 DESCRIPTOR_ASSERT(desc);
389 /* find a place in the hashtable */
390 key = utf_hashkey(desc->text, desc->blength);
391 slot = key & (pool->descriptorhash.size - 1);
392 c = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
395 return true; /* already stored */
398 /* add the descriptor to the pool */
399 c = DNEW(descriptor_hash_entry);
401 c->parseddesc.any = NULL;
402 c->hashlink = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
403 pool->descriptorhash.ptr[slot] = c;
405 /* now check the descriptor */
406 utf_ptr = desc->text;
407 end_pos = utf_end(desc);
409 if (*utf_ptr == '(') {
412 /* a method descriptor */
416 /* check arguments */
417 while (utf_ptr != end_pos && *utf_ptr != ')') {
419 /* We cannot count the this argument here because
420 * we don't know if the method is static. */
421 if (*utf_ptr == 'J' || *utf_ptr == 'D')
425 if (!name_from_descriptor(pool->referer,utf_ptr,end_pos,&utf_ptr,
426 DESCRIPTOR_NOVOID,&name))
430 descriptor_pool_add_class(pool,name);
433 if (utf_ptr == end_pos) {
434 *exceptionptr = new_classformaterror(pool->referer,"Missing ')' in method descriptor");
438 utf_ptr++; /* skip ')' */
440 if (!name_from_descriptor(pool->referer,utf_ptr,end_pos,NULL,
441 DESCRIPTOR_CHECKEND,&name))
445 descriptor_pool_add_class(pool,name);
447 if (argcount > 255) {
449 new_classformaterror(pool->referer,"Too many arguments in signature");
454 /* a field descriptor */
457 if (!name_from_descriptor(pool->referer,utf_ptr,end_pos,NULL,
459 | DESCRIPTOR_CHECKEND,&name))
463 descriptor_pool_add_class(pool,name);
469 /* descriptor_pool_create_classrefs ********************************************
471 Create a table containing all the classrefs which were added to the pool
474 pool.............the descriptor_pool
477 *count...........if count is non-NULL, this is set to the number
478 of classrefs in the table
481 a pointer to the constant_classref table
483 *******************************************************************************/
486 descriptor_pool_create_classrefs(descriptor_pool *pool,s4 *count)
490 classref_hash_entry *c;
491 constant_classref *ref;
493 DESCRIPTOR_ASSERT(pool);
495 nclasses = pool->classrefhash.entries;
496 pool->classrefs = MNEW(constant_classref,nclasses);
498 /* fill the constant_classref structs */
499 for (slot=0; slot<pool->classrefhash.size; ++slot) {
500 c = (classref_hash_entry *) pool->classrefhash.ptr[slot];
502 ref = pool->classrefs + c->index;
503 CLASSREF_INIT(*ref,pool->referer,c->name);
510 return pool->classrefs;
513 /* descriptor_pool_lookup_classref *********************************************
515 Return the constant_classref for the given class name
518 pool.............the descriptor_pool
519 classname........name of the class to look up
522 a pointer to the constant_classref, or
523 NULL if an exception has been thrown
525 *******************************************************************************/
528 descriptor_pool_lookup_classref(descriptor_pool *pool,utf *classname)
531 classref_hash_entry *c;
533 DESCRIPTOR_ASSERT(pool);
534 DESCRIPTOR_ASSERT(pool->classrefs);
535 DESCRIPTOR_ASSERT(classname);
537 key = utf_hashkey(classname->text, classname->blength);
538 slot = key & (pool->classrefhash.size - 1);
539 c = (classref_hash_entry *) pool->classrefhash.ptr[slot];
541 if (c->name == classname)
542 return pool->classrefs + c->index;
546 *exceptionptr = new_exception_message(string_java_lang_InternalError,
547 "Class reference not found in descriptor pool");
551 /* descriptor_pool_alloc_parsed_descriptors ************************************
553 Allocate space for the parsed descriptors
556 pool.............the descriptor_pool
559 This function must be called after all descriptors have been added
560 with descriptor_pool_add.
562 *******************************************************************************/
565 descriptor_pool_alloc_parsed_descriptors(descriptor_pool *pool)
569 DESCRIPTOR_ASSERT(pool);
571 size = pool->fieldcount * sizeof(typedesc)
572 + pool->methodcount * (sizeof(methoddesc) - sizeof(typedesc))
573 + pool->paramcount * sizeof(typedesc);
575 pool->descriptorsize = size;
577 pool->descriptors = MNEW(u1,size);
578 pool->descriptors_next = pool->descriptors;
581 size = pool->fieldcount + pool->methodcount;
583 pool->descriptor_kind = DMNEW(u1,size);
584 pool->descriptor_kind_next = pool->descriptor_kind;
588 /* descriptor_pool_parse_field_descriptor **************************************
590 Parse the given field descriptor
593 pool.............the descriptor_pool
594 desc.............the field descriptor
597 a pointer to the parsed field descriptor, or
598 NULL if an exception has been thrown
601 descriptor_pool_alloc_parsed_descriptors must be called (once) before this
604 *******************************************************************************/
607 descriptor_pool_parse_field_descriptor(descriptor_pool *pool,utf *desc)
610 descriptor_hash_entry *c;
613 DESCRIPTOR_ASSERT(pool);
614 DESCRIPTOR_ASSERT(pool->descriptors);
615 DESCRIPTOR_ASSERT(pool->descriptors_next);
617 /* lookup the descriptor in the hashtable */
618 key = utf_hashkey(desc->text, desc->blength);
619 slot = key & (pool->descriptorhash.size - 1);
620 c = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
622 if (c->desc == desc) {
624 if (c->parseddesc.fd)
625 return c->parseddesc.fd;
631 DESCRIPTOR_ASSERT(c);
633 if (desc->text[0] == '(') {
634 *exceptionptr = new_classformaterror(pool->referer,
635 "Method descriptor used in field reference");
639 d = (typedesc *) pool->descriptors_next;
640 pool->descriptors_next += sizeof(typedesc);
642 if (!descriptor_to_typedesc(pool,desc->text,utf_end(desc),NULL,d))
645 *(pool->descriptor_kind_next++) = 'f';
647 c->parseddesc.fd = d;
651 /* descriptor_pool_parse_method_descriptor *************************************
653 Parse the given method descriptor
656 pool.............the descriptor_pool
657 desc.............the method descriptor
660 a pointer to the parsed method descriptor, or
661 NULL if an exception has been thrown
664 descriptor_pool_alloc_parsed_descriptors must be called (once) before this
667 *******************************************************************************/
670 descriptor_pool_parse_method_descriptor(descriptor_pool *pool,utf *desc)
673 descriptor_hash_entry *c;
681 DESCRIPTOR_ASSERT(pool);
682 DESCRIPTOR_ASSERT(pool->descriptors);
683 DESCRIPTOR_ASSERT(pool->descriptors_next);
685 /* lookup the descriptor in the hashtable */
686 key = utf_hashkey(desc->text, desc->blength);
687 slot = key & (pool->descriptorhash.size - 1);
688 c = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
690 if (c->desc == desc) {
692 if (c->parseddesc.md)
693 return c->parseddesc.md;
699 DESCRIPTOR_ASSERT(c);
701 md = (methoddesc *) pool->descriptors_next;
702 pool->descriptors_next += sizeof(methoddesc) - sizeof(typedesc);
704 utf_ptr = desc->text;
705 end_pos = utf_end(desc);
707 if (*utf_ptr++ != '(') {
708 *exceptionptr = new_classformaterror(pool->referer,
709 "Field descriptor used in method reference");
714 while (*utf_ptr != ')') {
715 /* parse a parameter type */
716 if (!descriptor_to_typedesc(pool,utf_ptr,end_pos,&utf_ptr,d))
719 if (d->type == TYPE_LONG || d->type == TYPE_DOUBLE)
723 pool->descriptors_next += sizeof(typedesc);
727 utf_ptr++; /* skip ')' */
729 /* parse return type */
730 if (!descriptor_to_typedesc(pool,utf_ptr,end_pos,NULL,&(md->returntype)))
733 md->paramcount = paramcount;
734 md->paramslots = paramslots;
735 *(pool->descriptor_kind_next++) = 'm';
736 c->parseddesc.md = md;
740 /* descriptor_pool_get_parsed_descriptors **************************************
742 Return a pointer to the block of parsed descriptors
745 pool.............the descriptor_pool
748 *size............if size is non-NULL, this is set to the size of the
749 parsed descriptor block (in u1)
752 a pointer to the block of parsed descriptors
755 descriptor_pool_alloc_parsed_descriptors must be called (once) before this
758 *******************************************************************************/
761 descriptor_pool_get_parsed_descriptors(descriptor_pool *pool,s4 *size)
763 DESCRIPTOR_ASSERT(pool);
764 DESCRIPTOR_ASSERT((!pool->fieldcount && !pool->methodcount) || pool->descriptors);
767 *size = pool->descriptorsize;
768 return pool->descriptors;
771 /* descriptor_pool_get_sizes ***************************************************
773 Get the sizes of the class reference table and the parsed descriptors
776 pool.............the descriptor_pool
779 *classrefsize....set to size of the class reference table
780 *descsize........set to size of the parsed descriptors
783 This function may only be called after both
784 descriptor_pool_create_classrefs, and
785 descriptor_pool_alloc_parsed_descriptors
788 *******************************************************************************/
791 descriptor_pool_get_sizes(descriptor_pool *pool,
792 u4 *classrefsize,u4 *descsize)
794 DESCRIPTOR_ASSERT(pool);
795 DESCRIPTOR_ASSERT((!pool->fieldcount && !pool->methodcount) || pool->descriptors);
796 DESCRIPTOR_ASSERT(pool->classrefs);
797 DESCRIPTOR_ASSERT(classrefsize);
798 DESCRIPTOR_ASSERT(descsize);
800 *classrefsize = pool->classrefhash.entries * sizeof(constant_classref);
801 *descsize = pool->descriptorsize;
804 /* descriptor_debug_print_typedesc *********************************************
806 Print the given typedesc to the given stream
809 file.............stream to print to
810 d................the parsed descriptor
812 *******************************************************************************/
815 descriptor_debug_print_typedesc(FILE *file,typedesc *d)
820 fprintf(file,"(typedesc *)NULL");
824 if (d->type == TYPE_ADDRESS) {
825 utf_fprint(file,d->classref->name);
829 case TYPE_INT : ch='I'; break;
830 case TYPE_LONG : ch='J'; break;
831 case TYPE_FLOAT : ch='F'; break;
832 case TYPE_DOUBLE : ch='D'; break;
833 case TYPE_ADDRESS: ch='A'; break;
834 case TYPE_VOID : ch='V'; break;
840 fprintf(file,"[%d]",d->arraydim);
843 /* descriptor_debug_print_methoddesc *******************************************
845 Print the given methoddesc to the given stream
848 file.............stream to print to
849 d................the parsed descriptor
851 *******************************************************************************/
854 descriptor_debug_print_methoddesc(FILE *file,methoddesc *d)
859 fprintf(file,"(methoddesc *)NULL");
864 for (i=0; i<d->paramcount; ++i) {
867 descriptor_debug_print_typedesc(file,d->paramtypes + i);
870 descriptor_debug_print_typedesc(file,&(d->returntype));
873 /* descriptor_pool_debug_dump **************************************************
875 Print the state of the descriptor_pool to the given stream
878 pool.............the descriptor_pool
879 file.............stream to print to
881 *******************************************************************************/
884 descriptor_pool_debug_dump(descriptor_pool *pool,FILE *file)
891 fprintf(file,"======[descriptor_pool for ");
892 utf_fprint(file,pool->referer->name);
893 fprintf(file,"]======\n");
895 fprintf(file,"fieldcount: %d\n",pool->fieldcount);
896 fprintf(file,"methodcount: %d\n",pool->methodcount);
897 fprintf(file,"paramcount: %d\n",pool->paramcount);
898 fprintf(file,"classrefcount: %d\n",pool->classrefhash.entries);
899 fprintf(file,"descriptorsize: %d bytes\n",pool->descriptorsize);
900 fprintf(file,"classrefsize: %d bytes\n",
901 pool->classrefhash.entries * sizeof(constant_classref));
903 fprintf(file,"class references:\n");
904 for (slot=0; slot<pool->classrefhash.size; ++slot) {
905 classref_hash_entry *c = (classref_hash_entry *) pool->classrefhash.ptr[slot];
907 fprintf(file," %4d: ",c->index);
908 utf_fprint(file,c->name);
914 fprintf(file,"hashed descriptors:\n");
915 for (slot=0; slot<pool->descriptorhash.size; ++slot) {
916 descriptor_hash_entry *c = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
918 fprintf(file," %p: ",c->parseddesc.any);
919 utf_fprint(file,c->desc);
925 fprintf(file,"descriptors:\n");
926 if (pool->descriptors) {
927 pos = pool->descriptors;
928 size = pool->descriptors_next - pool->descriptors;
929 fprintf(file," size: %d bytes\n",size);
931 if (pool->descriptor_kind) {
932 kind = pool->descriptor_kind;
934 while (pos < (pool->descriptors + size)) {
935 fprintf(file," %p: ",pos);
938 descriptor_debug_print_typedesc(file,(typedesc*)pos);
939 pos += sizeof(typedesc);
942 descriptor_debug_print_methoddesc(file,(methoddesc*)pos);
943 pos += ((methoddesc*)pos)->paramcount * sizeof(typedesc);
944 pos += sizeof(methoddesc) - sizeof(typedesc);
947 fprintf(file,"INVALID KIND");
953 while (size >= sizeof(voidptr)) {
954 fprintf(file," %p\n",*((voidptr*)pos));
955 pos += sizeof(voidptr);
956 size -= sizeof(voidptr);
961 fprintf(file,"==========================================================\n");
965 * These are local overrides for various environment variables in Emacs.
966 * Please do not remove this and leave it at the end of the file, where
967 * Emacs will automagically detect them.
968 * ---------------------------------------------------------------------
971 * indent-tabs-mode: t
975 * vim:noexpandtab:sw=4:ts=4: