1 /* src/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
29 Changes: Christian Thalinger
31 $Id: descriptor.c 2458 2005-05-12 23:02:07Z twisti $
39 #include "mm/memory.h"
40 #include "vm/descriptor.h"
41 #include "vm/exceptions.h"
42 #include "vm/resolve.h"
43 #include "vm/stringlocal.h"
46 /* constants (private to descriptor.c) ****************************************/
48 /* initial number of entries for the classrefhash of a descriptor_pool */
49 /* (currently the hash is never grown!) */
50 #define CLASSREFHASH_INIT_SIZE 64
52 /* initial number of entries for the descriptorhash of a descriptor_pool */
53 /* (currently the hash is never grown!) */
54 #define DESCRIPTORHASH_INIT_SIZE 128
56 /* data structures (private to descriptor.c) **********************************/
58 typedef struct classref_hash_entry classref_hash_entry;
59 typedef struct descriptor_hash_entry descriptor_hash_entry;
61 /* entry struct for the classrefhash of descriptor_pool */
62 struct classref_hash_entry {
63 classref_hash_entry *hashlink; /* for hash chaining */
64 utf *name; /* name of the class refered to */
65 u2 index; /* index into classref table */
68 /* entry struct for the descriptorhash of descriptor_pool */
69 struct descriptor_hash_entry {
70 descriptor_hash_entry *hashlink;
72 parseddesc parseddesc;
73 s2 paramslots; /* number of params, LONG/DOUBLE counted as 2 */
76 /****************************************************************************/
78 /****************************************************************************/
81 #define DESCRIPTOR_DEBUG
84 #ifdef DESCRIPTOR_DEBUG
85 #define DESCRIPTOR_ASSERT(cond) assert(cond)
87 #define DESCRIPTOR_ASSERT(cond)
90 /* name_from_descriptor ********************************************************
92 Return the class name indicated by the given descriptor
93 (Internally used helper function)
96 c................class containing the descriptor
97 utf_ptr..........first character of descriptor
98 end_ptr..........first character after the end of the string
99 mode.............a combination (binary or) of the following flags:
101 (Flags marked with * are the default settings.)
103 How to handle "V" descriptors:
105 * DESCRIPTOR_VOID.....handle it like other primitive types
106 DESCRIPTOR_NOVOID...treat it as an error
108 How to deal with extra characters after the end of the
111 * DESCRIPTOR_NOCHECKEND...ignore (useful for parameter lists)
112 DESCRIPTOR_CHECKEND.....treat them as an error
115 *next............if non-NULL, *next is set to the first character after
116 the descriptor. (Undefined if an error occurs.)
117 *name............set to the utf name of the class
120 true.............descriptor parsed successfully
121 false............an exception has been thrown
123 *******************************************************************************/
125 #define DESCRIPTOR_VOID 0 /* default */
126 #define DESCRIPTOR_NOVOID 0x0040
127 #define DESCRIPTOR_NOCHECKEND 0 /* default */
128 #define DESCRIPTOR_CHECKEND 0x1000
131 name_from_descriptor(classinfo *c,
132 char *utf_ptr, char *end_ptr,
133 char **next, int mode, utf **name)
135 char *start = utf_ptr;
138 DESCRIPTOR_ASSERT(c);
139 DESCRIPTOR_ASSERT(utf_ptr);
140 DESCRIPTOR_ASSERT(end_ptr);
141 DESCRIPTOR_ASSERT(name);
144 SKIP_FIELDDESCRIPTOR_SAFE(utf_ptr, end_ptr, error);
146 if (mode & DESCRIPTOR_CHECKEND)
147 error |= (utf_ptr != end_ptr);
150 if (next) *next = utf_ptr;
154 if (mode & DESCRIPTOR_NOVOID)
172 *name = utf_new(start, utf_ptr - start);
177 *exceptionptr = new_classformaterror(c,"invalid descriptor");
181 /* descriptor_to_typedesc ******************************************************
183 Parse the given type descriptor and fill a typedesc struct
184 (Internally used helper function)
187 pool.............the descriptor pool
188 utf_ptr..........points to first character of type descriptor
189 end_pos..........points after last character of the whole descriptor
192 *next............set to next character after type descriptor
193 *d...............filled with parsed information
196 true.............parsing succeeded
197 false............an exception has been thrown
199 *******************************************************************************/
202 descriptor_to_typedesc(descriptor_pool *pool,char *utf_ptr,char *end_pos,
203 char **next,typedesc *d)
207 if (!name_from_descriptor(pool->referer,utf_ptr,end_pos,next,0,&name))
211 /* a reference type */
212 d->type = TYPE_ADDRESS;
213 d->decltype = TYPE_ADDRESS;
215 for (utf_ptr=name->text; *utf_ptr == '['; ++utf_ptr)
217 d->classref = descriptor_pool_lookup_classref(pool,name);
220 /* a primitive type */
223 d->decltype = PRIMITIVETYPE_BYTE;
226 d->decltype = PRIMITIVETYPE_CHAR;
229 d->decltype = PRIMITIVETYPE_SHORT;
232 d->decltype = PRIMITIVETYPE_BOOLEAN;
235 d->decltype = PRIMITIVETYPE_INT;
241 d->decltype = PRIMITIVETYPE_DOUBLE;
242 d->type = TYPE_DOUBLE;
245 d->decltype = PRIMITIVETYPE_FLOAT;
246 d->type = TYPE_FLOAT;
249 d->decltype = PRIMITIVETYPE_LONG;
253 d->decltype = PRIMITIVETYPE_VOID;
257 DESCRIPTOR_ASSERT(false);
266 /* descriptor_pool_new *********************************************************
268 Allocate a new descriptor_pool
271 referer..........class for which to create the pool
274 a pointer to the new descriptor_pool
276 *******************************************************************************/
279 descriptor_pool_new(classinfo *referer)
281 descriptor_pool *pool;
285 pool = DNEW(descriptor_pool);
286 DESCRIPTOR_ASSERT(pool);
288 pool->referer = referer;
289 pool->fieldcount = 0;
290 pool->methodcount = 0;
291 pool->paramcount = 0;
292 pool->descriptorsize = 0;
293 pool->descriptors = NULL;
294 pool->descriptors_next = NULL;
295 pool->classrefs = NULL;
296 pool->descriptor_kind = NULL;
297 pool->descriptor_kind_next = NULL;
299 hashsize = CLASSREFHASH_INIT_SIZE;
300 pool->classrefhash.size = hashsize;
301 pool->classrefhash.entries = 0;
302 pool->classrefhash.ptr = DMNEW(voidptr,hashsize);
303 for (slot=0; slot<hashsize; ++slot)
304 pool->classrefhash.ptr[slot] = NULL;
306 hashsize = DESCRIPTORHASH_INIT_SIZE;
307 pool->descriptorhash.size = hashsize;
308 pool->descriptorhash.entries = 0;
309 pool->descriptorhash.ptr = DMNEW(voidptr,hashsize);
310 for (slot=0; slot<hashsize; ++slot)
311 pool->descriptorhash.ptr[slot] = NULL;
316 /* descriptor_pool_add_class ***************************************************
318 Add the given class reference to the pool
321 pool.............the descriptor_pool
322 name.............the class reference to add
325 true.............reference has been added
326 false............an exception has been thrown
328 *******************************************************************************/
331 descriptor_pool_add_class(descriptor_pool *pool,utf *name)
334 classref_hash_entry *c;
336 DESCRIPTOR_ASSERT(pool);
337 DESCRIPTOR_ASSERT(name);
339 /* find a place in the hashtable */
340 key = utf_hashkey(name->text, name->blength);
341 slot = key & (pool->classrefhash.size - 1);
342 c = (classref_hash_entry *) pool->classrefhash.ptr[slot];
345 return true; /* already stored */
349 /* check if the name is a valid classname */
350 if (!is_valid_name(name->text,utf_end(name))) {
351 *exceptionptr = new_classformaterror(pool->referer,"Invalid class name");
352 return false; /* exception */
355 /* XXX check maximum array dimension */
357 c = DNEW(classref_hash_entry);
359 c->index = pool->classrefhash.entries++;
360 c->hashlink = (classref_hash_entry *) pool->classrefhash.ptr[slot];
361 pool->classrefhash.ptr[slot] = c;
366 /* descriptor_pool_add *********************************************************
368 Check the given descriptor and add it to the pool
371 pool.............the descriptor_pool
372 desc.............the descriptor to add. Maybe a field or method desc.
375 *paramslots......if non-NULL, set to the number of parameters.
376 LONG and DOUBLE are counted twice
379 true.............descriptor has been added
380 false............an exception has been thrown
382 *******************************************************************************/
385 descriptor_pool_add(descriptor_pool *pool,utf *desc,int *paramslots)
388 descriptor_hash_entry *c;
394 DESCRIPTOR_ASSERT(pool);
395 DESCRIPTOR_ASSERT(desc);
397 /* find a place in the hashtable */
398 key = utf_hashkey(desc->text, desc->blength);
399 slot = key & (pool->descriptorhash.size - 1);
400 c = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
402 if (c->desc == desc) {
404 *paramslots = c->paramslots;
405 return true; /* already stored */
409 /* add the descriptor to the pool */
410 c = DNEW(descriptor_hash_entry);
412 c->parseddesc.any = NULL;
413 c->hashlink = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
414 pool->descriptorhash.ptr[slot] = c;
416 /* now check the descriptor */
417 utf_ptr = desc->text;
418 end_pos = utf_end(desc);
420 if (*utf_ptr == '(') {
421 /* a method descriptor */
425 /* check arguments */
426 while (utf_ptr != end_pos && *utf_ptr != ')') {
428 /* We cannot count the this argument here because
429 * we don't know if the method is static. */
430 if (*utf_ptr == 'J' || *utf_ptr == 'D')
434 if (!name_from_descriptor(pool->referer,utf_ptr,end_pos,&utf_ptr,
435 DESCRIPTOR_NOVOID,&name))
439 descriptor_pool_add_class(pool,name);
442 if (utf_ptr == end_pos) {
443 *exceptionptr = new_classformaterror(pool->referer,"Missing ')' in method descriptor");
447 utf_ptr++; /* skip ')' */
449 if (!name_from_descriptor(pool->referer,utf_ptr,end_pos,NULL,
450 DESCRIPTOR_CHECKEND,&name))
454 descriptor_pool_add_class(pool,name);
456 if (argcount > 255) {
458 new_classformaterror(pool->referer,"Too many arguments in signature");
463 /* a field descriptor */
466 if (!name_from_descriptor(pool->referer,utf_ptr,end_pos,NULL,
468 | DESCRIPTOR_CHECKEND,&name))
472 descriptor_pool_add_class(pool,name);
475 c->paramslots = argcount;
477 *paramslots = argcount;
482 /* descriptor_pool_create_classrefs ********************************************
484 Create a table containing all the classrefs which were added to the pool
487 pool.............the descriptor_pool
490 *count...........if count is non-NULL, this is set to the number
491 of classrefs in the table
494 a pointer to the constant_classref table
496 *******************************************************************************/
499 descriptor_pool_create_classrefs(descriptor_pool *pool,s4 *count)
503 classref_hash_entry *c;
504 constant_classref *ref;
506 DESCRIPTOR_ASSERT(pool);
508 nclasses = pool->classrefhash.entries;
509 pool->classrefs = MNEW(constant_classref,nclasses);
511 /* fill the constant_classref structs */
512 for (slot=0; slot<pool->classrefhash.size; ++slot) {
513 c = (classref_hash_entry *) pool->classrefhash.ptr[slot];
515 ref = pool->classrefs + c->index;
516 CLASSREF_INIT(*ref,pool->referer,c->name);
523 return pool->classrefs;
526 /* descriptor_pool_lookup_classref *********************************************
528 Return the constant_classref for the given class name
531 pool.............the descriptor_pool
532 classname........name of the class to look up
535 a pointer to the constant_classref, or
536 NULL if an exception has been thrown
538 *******************************************************************************/
541 descriptor_pool_lookup_classref(descriptor_pool *pool,utf *classname)
544 classref_hash_entry *c;
546 DESCRIPTOR_ASSERT(pool);
547 DESCRIPTOR_ASSERT(pool->classrefs);
548 DESCRIPTOR_ASSERT(classname);
550 key = utf_hashkey(classname->text, classname->blength);
551 slot = key & (pool->classrefhash.size - 1);
552 c = (classref_hash_entry *) pool->classrefhash.ptr[slot];
554 if (c->name == classname)
555 return pool->classrefs + c->index;
559 *exceptionptr = new_exception_message(string_java_lang_InternalError,
560 "Class reference not found in descriptor pool");
564 /* descriptor_pool_alloc_parsed_descriptors ************************************
566 Allocate space for the parsed descriptors
569 pool.............the descriptor_pool
572 This function must be called after all descriptors have been added
573 with descriptor_pool_add.
575 *******************************************************************************/
578 descriptor_pool_alloc_parsed_descriptors(descriptor_pool *pool)
582 DESCRIPTOR_ASSERT(pool);
584 size = pool->fieldcount * sizeof(typedesc)
585 + pool->methodcount * (sizeof(methoddesc) - sizeof(typedesc))
586 + pool->paramcount * sizeof(typedesc);
588 pool->descriptorsize = size;
590 pool->descriptors = MNEW(u1,size);
591 pool->descriptors_next = pool->descriptors;
594 size = pool->fieldcount + pool->methodcount;
596 pool->descriptor_kind = DMNEW(u1,size);
597 pool->descriptor_kind_next = pool->descriptor_kind;
601 /* descriptor_pool_parse_field_descriptor **************************************
603 Parse the given field descriptor
606 pool.............the descriptor_pool
607 desc.............the field descriptor
610 a pointer to the parsed field descriptor, or
611 NULL if an exception has been thrown
614 descriptor_pool_alloc_parsed_descriptors must be called (once) before this
617 *******************************************************************************/
620 descriptor_pool_parse_field_descriptor(descriptor_pool *pool,utf *desc)
623 descriptor_hash_entry *c;
626 DESCRIPTOR_ASSERT(pool);
627 DESCRIPTOR_ASSERT(pool->descriptors);
628 DESCRIPTOR_ASSERT(pool->descriptors_next);
630 /* lookup the descriptor in the hashtable */
631 key = utf_hashkey(desc->text, desc->blength);
632 slot = key & (pool->descriptorhash.size - 1);
633 c = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
635 if (c->desc == desc) {
637 if (c->parseddesc.fd)
638 return c->parseddesc.fd;
644 DESCRIPTOR_ASSERT(c);
646 if (desc->text[0] == '(') {
647 *exceptionptr = new_classformaterror(pool->referer,
648 "Method descriptor used in field reference");
652 d = (typedesc *) pool->descriptors_next;
653 pool->descriptors_next += sizeof(typedesc);
655 if (!descriptor_to_typedesc(pool,desc->text,utf_end(desc),NULL,d))
658 *(pool->descriptor_kind_next++) = 'f';
660 c->parseddesc.fd = d;
664 /* descriptor_pool_parse_method_descriptor *************************************
666 Parse the given method descriptor
669 pool.............the descriptor_pool
670 desc.............the method descriptor
673 a pointer to the parsed method descriptor, or
674 NULL if an exception has been thrown
677 descriptor_pool_alloc_parsed_descriptors must be called (once) before this
680 *******************************************************************************/
683 descriptor_pool_parse_method_descriptor(descriptor_pool *pool,utf *desc)
686 descriptor_hash_entry *c;
694 DESCRIPTOR_ASSERT(pool);
695 DESCRIPTOR_ASSERT(pool->descriptors);
696 DESCRIPTOR_ASSERT(pool->descriptors_next);
698 /* lookup the descriptor in the hashtable */
699 key = utf_hashkey(desc->text, desc->blength);
700 slot = key & (pool->descriptorhash.size - 1);
701 c = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
703 if (c->desc == desc) {
705 if (c->parseddesc.md)
706 return c->parseddesc.md;
712 DESCRIPTOR_ASSERT(c);
714 md = (methoddesc *) pool->descriptors_next;
715 pool->descriptors_next += sizeof(methoddesc) - sizeof(typedesc);
717 utf_ptr = desc->text;
718 end_pos = utf_end(desc);
720 if (*utf_ptr++ != '(') {
721 *exceptionptr = new_classformaterror(pool->referer,
722 "Field descriptor used in method reference");
727 while (*utf_ptr != ')') {
728 /* parse a parameter type */
729 if (!descriptor_to_typedesc(pool,utf_ptr,end_pos,&utf_ptr,d))
732 if (d->type == TYPE_LONG || d->type == TYPE_DOUBLE)
736 pool->descriptors_next += sizeof(typedesc);
740 utf_ptr++; /* skip ')' */
742 /* parse return type */
743 if (!descriptor_to_typedesc(pool,utf_ptr,end_pos,NULL,&(md->returntype)))
746 md->paramcount = paramcount;
747 md->paramslots = paramslots;
748 *(pool->descriptor_kind_next++) = 'm';
749 c->parseddesc.md = md;
753 /* descriptor_pool_get_parsed_descriptors **************************************
755 Return a pointer to the block of parsed descriptors
758 pool.............the descriptor_pool
761 *size............if size is non-NULL, this is set to the size of the
762 parsed descriptor block (in u1)
765 a pointer to the block of parsed descriptors
768 descriptor_pool_alloc_parsed_descriptors must be called (once) before this
771 *******************************************************************************/
774 descriptor_pool_get_parsed_descriptors(descriptor_pool *pool,s4 *size)
776 DESCRIPTOR_ASSERT(pool);
777 DESCRIPTOR_ASSERT((!pool->fieldcount && !pool->methodcount) || pool->descriptors);
780 *size = pool->descriptorsize;
781 return pool->descriptors;
784 /* descriptor_pool_get_sizes ***************************************************
786 Get the sizes of the class reference table and the parsed descriptors
789 pool.............the descriptor_pool
792 *classrefsize....set to size of the class reference table
793 *descsize........set to size of the parsed descriptors
796 This function may only be called after both
797 descriptor_pool_create_classrefs, and
798 descriptor_pool_alloc_parsed_descriptors
801 *******************************************************************************/
804 descriptor_pool_get_sizes(descriptor_pool *pool,
805 u4 *classrefsize,u4 *descsize)
807 DESCRIPTOR_ASSERT(pool);
808 DESCRIPTOR_ASSERT((!pool->fieldcount && !pool->methodcount) || pool->descriptors);
809 DESCRIPTOR_ASSERT(pool->classrefs);
810 DESCRIPTOR_ASSERT(classrefsize);
811 DESCRIPTOR_ASSERT(descsize);
813 *classrefsize = pool->classrefhash.entries * sizeof(constant_classref);
814 *descsize = pool->descriptorsize;
817 /* descriptor_debug_print_typedesc *********************************************
819 Print the given typedesc to the given stream
822 file.............stream to print to
823 d................the parsed descriptor
825 *******************************************************************************/
828 descriptor_debug_print_typedesc(FILE *file,typedesc *d)
833 fprintf(file,"(typedesc *)NULL");
837 if (d->type == TYPE_ADDRESS) {
838 utf_fprint(file,d->classref->name);
841 switch (d->decltype) {
842 case PRIMITIVETYPE_INT : ch='I'; break;
843 case PRIMITIVETYPE_CHAR : ch='C'; break;
844 case PRIMITIVETYPE_BYTE : ch='B'; break;
845 case PRIMITIVETYPE_SHORT : ch='S'; break;
846 case PRIMITIVETYPE_BOOLEAN: ch='Z'; break;
847 case PRIMITIVETYPE_LONG : ch='J'; break;
848 case PRIMITIVETYPE_FLOAT : ch='F'; break;
849 case PRIMITIVETYPE_DOUBLE : ch='D'; break;
850 case PRIMITIVETYPE_VOID : ch='V'; break;
856 fprintf(file,"[%d]",d->arraydim);
859 /* descriptor_debug_print_methoddesc *******************************************
861 Print the given methoddesc to the given stream
864 file.............stream to print to
865 d................the parsed descriptor
867 *******************************************************************************/
870 descriptor_debug_print_methoddesc(FILE *file,methoddesc *d)
875 fprintf(file,"(methoddesc *)NULL");
880 for (i=0; i<d->paramcount; ++i) {
883 descriptor_debug_print_typedesc(file,d->paramtypes + i);
886 descriptor_debug_print_typedesc(file,&(d->returntype));
889 /* descriptor_pool_debug_dump **************************************************
891 Print the state of the descriptor_pool to the given stream
894 pool.............the descriptor_pool
895 file.............stream to print to
897 *******************************************************************************/
900 descriptor_pool_debug_dump(descriptor_pool *pool,FILE *file)
907 fprintf(file,"======[descriptor_pool for ");
908 utf_fprint(file,pool->referer->name);
909 fprintf(file,"]======\n");
911 fprintf(file,"fieldcount: %d\n",pool->fieldcount);
912 fprintf(file,"methodcount: %d\n",pool->methodcount);
913 fprintf(file,"paramcount: %d\n",pool->paramcount);
914 fprintf(file,"classrefcount: %d\n",pool->classrefhash.entries);
915 fprintf(file,"descriptorsize: %d bytes\n",pool->descriptorsize);
916 fprintf(file,"classrefsize: %d bytes\n",
917 (int)(pool->classrefhash.entries * sizeof(constant_classref)));
919 fprintf(file,"class references:\n");
920 for (slot=0; slot<pool->classrefhash.size; ++slot) {
921 classref_hash_entry *c = (classref_hash_entry *) pool->classrefhash.ptr[slot];
923 fprintf(file," %4d: ",c->index);
924 utf_fprint(file,c->name);
930 fprintf(file,"hashed descriptors:\n");
931 for (slot=0; slot<pool->descriptorhash.size; ++slot) {
932 descriptor_hash_entry *c = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
934 fprintf(file," %p: ",c->parseddesc.any);
935 utf_fprint(file,c->desc);
941 fprintf(file,"descriptors:\n");
942 if (pool->descriptors) {
943 pos = pool->descriptors;
944 size = pool->descriptors_next - pool->descriptors;
945 fprintf(file," size: %d bytes\n",size);
947 if (pool->descriptor_kind) {
948 kind = pool->descriptor_kind;
950 while (pos < (pool->descriptors + size)) {
951 fprintf(file," %p: ",pos);
954 descriptor_debug_print_typedesc(file,(typedesc*)pos);
955 pos += sizeof(typedesc);
958 descriptor_debug_print_methoddesc(file,(methoddesc*)pos);
959 pos += ((methoddesc*)pos)->paramcount * sizeof(typedesc);
960 pos += sizeof(methoddesc) - sizeof(typedesc);
963 fprintf(file,"INVALID KIND");
969 while (size >= sizeof(voidptr)) {
970 fprintf(file," %p\n",*((voidptr*)pos));
971 pos += sizeof(voidptr);
972 size -= sizeof(voidptr);
977 fprintf(file,"==========================================================\n");
981 * These are local overrides for various environment variables in Emacs.
982 * Please do not remove this and leave it at the end of the file, where
983 * Emacs will automagically detect them.
984 * ---------------------------------------------------------------------
987 * indent-tabs-mode: t
991 * vim:noexpandtab:sw=4:ts=4: