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 2186 2005-04-02 00:43:25Z 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;
69 s2 paramslots; /* number of params, LONG/DOUBLE counted as 2 */
72 /****************************************************************************/
74 /****************************************************************************/
77 #define DESCRIPTOR_DEBUG
80 #ifdef DESCRIPTOR_DEBUG
81 #define DESCRIPTOR_ASSERT(cond) assert(cond)
83 #define DESCRIPTOR_ASSERT(cond)
86 /* name_from_descriptor ********************************************************
88 Return the class name indicated by the given descriptor
89 (Internally used helper function)
92 c................class containing the descriptor
93 utf_ptr..........first character of descriptor
94 end_ptr..........first character after the end of the string
95 mode.............a combination (binary or) of the following flags:
97 (Flags marked with * are the default settings.)
99 How to handle "V" descriptors:
101 * DESCRIPTOR_VOID.....handle it like other primitive types
102 DESCRIPTOR_NOVOID...treat it as an error
104 How to deal with extra characters after the end of the
107 * DESCRIPTOR_NOCHECKEND...ignore (useful for parameter lists)
108 DESCRIPTOR_CHECKEND.....treat them as an error
111 *next............if non-NULL, *next is set to the first character after
112 the descriptor. (Undefined if an error occurs.)
113 *name............set to the utf name of the class
116 true.............descriptor parsed successfully
117 false............an exception has been thrown
119 *******************************************************************************/
121 #define DESCRIPTOR_VOID 0 /* default */
122 #define DESCRIPTOR_NOVOID 0x0040
123 #define DESCRIPTOR_NOCHECKEND 0 /* default */
124 #define DESCRIPTOR_CHECKEND 0x1000
127 name_from_descriptor(classinfo *c,
128 char *utf_ptr, char *end_ptr,
129 char **next, int mode, utf **name)
131 char *start = utf_ptr;
134 DESCRIPTOR_ASSERT(c);
135 DESCRIPTOR_ASSERT(utf_ptr);
136 DESCRIPTOR_ASSERT(end_ptr);
137 DESCRIPTOR_ASSERT(name);
140 SKIP_FIELDDESCRIPTOR_SAFE(utf_ptr, end_ptr, error);
142 if (mode & DESCRIPTOR_CHECKEND)
143 error |= (utf_ptr != end_ptr);
146 if (next) *next = utf_ptr;
150 if (mode & DESCRIPTOR_NOVOID)
168 *name = utf_new(start, utf_ptr - start);
173 *exceptionptr = new_classformaterror(c,"invalid descriptor");
177 /* descriptor_to_typedesc ******************************************************
179 Parse the given type descriptor and fill a typedesc struct
180 (Internally used helper function)
183 pool.............the descriptor pool
184 utf_ptr..........points to first character of type descriptor
185 end_pos..........points after last character of the whole descriptor
188 *next............set to next character after type descriptor
189 *d...............filled with parsed information
192 true.............parsing succeeded
193 false............an exception has been thrown
195 *******************************************************************************/
198 descriptor_to_typedesc(descriptor_pool *pool,char *utf_ptr,char *end_pos,
199 char **next,typedesc *d)
203 if (!name_from_descriptor(pool->referer,utf_ptr,end_pos,next,0,&name))
207 /* a reference type */
208 d->type = TYPE_ADDRESS;
209 d->decltype = TYPE_ADDRESS;
211 for (utf_ptr=name->text; *utf_ptr == '['; ++utf_ptr)
213 d->classref = descriptor_pool_lookup_classref(pool,name);
216 /* a primitive type */
219 d->decltype = PRIMITIVETYPE_BYTE;
222 d->decltype = PRIMITIVETYPE_CHAR;
225 d->decltype = PRIMITIVETYPE_SHORT;
228 d->decltype = PRIMITIVETYPE_BOOLEAN;
231 d->decltype = PRIMITIVETYPE_INT;
237 d->decltype = PRIMITIVETYPE_DOUBLE;
238 d->type = TYPE_DOUBLE;
241 d->decltype = PRIMITIVETYPE_FLOAT;
242 d->type = TYPE_FLOAT;
245 d->decltype = PRIMITIVETYPE_LONG;
249 d->decltype = PRIMITIVETYPE_VOID;
253 DESCRIPTOR_ASSERT(false);
262 /* descriptor_pool_new *********************************************************
264 Allocate a new descriptor_pool
267 referer..........class for which to create the pool
270 a pointer to the new descriptor_pool
272 *******************************************************************************/
275 descriptor_pool_new(classinfo *referer)
277 descriptor_pool *pool;
281 pool = DNEW(descriptor_pool);
282 DESCRIPTOR_ASSERT(pool);
284 pool->referer = referer;
285 pool->fieldcount = 0;
286 pool->methodcount = 0;
287 pool->paramcount = 0;
288 pool->descriptorsize = 0;
289 pool->descriptors = NULL;
290 pool->descriptors_next = NULL;
291 pool->classrefs = NULL;
292 pool->descriptor_kind = NULL;
293 pool->descriptor_kind_next = NULL;
295 hashsize = CLASSREFHASH_INIT_SIZE;
296 pool->classrefhash.size = hashsize;
297 pool->classrefhash.entries = 0;
298 pool->classrefhash.ptr = DMNEW(voidptr,hashsize);
299 for (slot=0; slot<hashsize; ++slot)
300 pool->classrefhash.ptr[slot] = NULL;
302 hashsize = DESCRIPTORHASH_INIT_SIZE;
303 pool->descriptorhash.size = hashsize;
304 pool->descriptorhash.entries = 0;
305 pool->descriptorhash.ptr = DMNEW(voidptr,hashsize);
306 for (slot=0; slot<hashsize; ++slot)
307 pool->descriptorhash.ptr[slot] = NULL;
312 /* descriptor_pool_add_class ***************************************************
314 Add the given class reference to the pool
317 pool.............the descriptor_pool
318 name.............the class reference to add
321 true.............reference has been added
322 false............an exception has been thrown
324 *******************************************************************************/
327 descriptor_pool_add_class(descriptor_pool *pool,utf *name)
330 classref_hash_entry *c;
332 DESCRIPTOR_ASSERT(pool);
333 DESCRIPTOR_ASSERT(name);
335 /* find a place in the hashtable */
336 key = utf_hashkey(name->text, name->blength);
337 slot = key & (pool->classrefhash.size - 1);
338 c = (classref_hash_entry *) pool->classrefhash.ptr[slot];
341 return true; /* already stored */
345 /* check if the name is a valid classname */
346 if (!is_valid_name(name->text,utf_end(name))) {
347 *exceptionptr = new_classformaterror(pool->referer,"Invalid class name");
348 return false; /* exception */
351 /* XXX check maximum array dimension */
353 c = DNEW(classref_hash_entry);
355 c->index = pool->classrefhash.entries++;
356 c->hashlink = (classref_hash_entry *) pool->classrefhash.ptr[slot];
357 pool->classrefhash.ptr[slot] = c;
362 /* descriptor_pool_add *********************************************************
364 Check the given descriptor and add it to the pool
367 pool.............the descriptor_pool
368 desc.............the descriptor to add. Maybe a field or method desc.
371 *paramslots......if non-NULL, set to the number of parameters.
372 LONG and DOUBLE are counted twice
375 true.............descriptor has been added
376 false............an exception has been thrown
378 *******************************************************************************/
381 descriptor_pool_add(descriptor_pool *pool,utf *desc,int *paramslots)
384 descriptor_hash_entry *c;
390 DESCRIPTOR_ASSERT(pool);
391 DESCRIPTOR_ASSERT(desc);
393 /* find a place in the hashtable */
394 key = utf_hashkey(desc->text, desc->blength);
395 slot = key & (pool->descriptorhash.size - 1);
396 c = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
398 if (c->desc == desc) {
400 *paramslots = c->paramslots;
401 return true; /* already stored */
405 /* add the descriptor to the pool */
406 c = DNEW(descriptor_hash_entry);
408 c->parseddesc.any = NULL;
409 c->hashlink = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
410 pool->descriptorhash.ptr[slot] = c;
412 /* now check the descriptor */
413 utf_ptr = desc->text;
414 end_pos = utf_end(desc);
416 if (*utf_ptr == '(') {
417 /* a method descriptor */
421 /* check arguments */
422 while (utf_ptr != end_pos && *utf_ptr != ')') {
424 /* We cannot count the this argument here because
425 * we don't know if the method is static. */
426 if (*utf_ptr == 'J' || *utf_ptr == 'D')
430 if (!name_from_descriptor(pool->referer,utf_ptr,end_pos,&utf_ptr,
431 DESCRIPTOR_NOVOID,&name))
435 descriptor_pool_add_class(pool,name);
438 if (utf_ptr == end_pos) {
439 *exceptionptr = new_classformaterror(pool->referer,"Missing ')' in method descriptor");
443 utf_ptr++; /* skip ')' */
445 if (!name_from_descriptor(pool->referer,utf_ptr,end_pos,NULL,
446 DESCRIPTOR_CHECKEND,&name))
450 descriptor_pool_add_class(pool,name);
452 if (argcount > 255) {
454 new_classformaterror(pool->referer,"Too many arguments in signature");
459 /* a field descriptor */
462 if (!name_from_descriptor(pool->referer,utf_ptr,end_pos,NULL,
464 | DESCRIPTOR_CHECKEND,&name))
468 descriptor_pool_add_class(pool,name);
471 c->paramslots = argcount;
473 *paramslots = argcount;
478 /* descriptor_pool_create_classrefs ********************************************
480 Create a table containing all the classrefs which were added to the pool
483 pool.............the descriptor_pool
486 *count...........if count is non-NULL, this is set to the number
487 of classrefs in the table
490 a pointer to the constant_classref table
492 *******************************************************************************/
495 descriptor_pool_create_classrefs(descriptor_pool *pool,s4 *count)
499 classref_hash_entry *c;
500 constant_classref *ref;
502 DESCRIPTOR_ASSERT(pool);
504 nclasses = pool->classrefhash.entries;
505 pool->classrefs = MNEW(constant_classref,nclasses);
507 /* fill the constant_classref structs */
508 for (slot=0; slot<pool->classrefhash.size; ++slot) {
509 c = (classref_hash_entry *) pool->classrefhash.ptr[slot];
511 ref = pool->classrefs + c->index;
512 CLASSREF_INIT(*ref,pool->referer,c->name);
519 return pool->classrefs;
522 /* descriptor_pool_lookup_classref *********************************************
524 Return the constant_classref for the given class name
527 pool.............the descriptor_pool
528 classname........name of the class to look up
531 a pointer to the constant_classref, or
532 NULL if an exception has been thrown
534 *******************************************************************************/
537 descriptor_pool_lookup_classref(descriptor_pool *pool,utf *classname)
540 classref_hash_entry *c;
542 DESCRIPTOR_ASSERT(pool);
543 DESCRIPTOR_ASSERT(pool->classrefs);
544 DESCRIPTOR_ASSERT(classname);
546 key = utf_hashkey(classname->text, classname->blength);
547 slot = key & (pool->classrefhash.size - 1);
548 c = (classref_hash_entry *) pool->classrefhash.ptr[slot];
550 if (c->name == classname)
551 return pool->classrefs + c->index;
555 *exceptionptr = new_exception_message(string_java_lang_InternalError,
556 "Class reference not found in descriptor pool");
560 /* descriptor_pool_alloc_parsed_descriptors ************************************
562 Allocate space for the parsed descriptors
565 pool.............the descriptor_pool
568 This function must be called after all descriptors have been added
569 with descriptor_pool_add.
571 *******************************************************************************/
574 descriptor_pool_alloc_parsed_descriptors(descriptor_pool *pool)
578 DESCRIPTOR_ASSERT(pool);
580 size = pool->fieldcount * sizeof(typedesc)
581 + pool->methodcount * (sizeof(methoddesc) - sizeof(typedesc))
582 + pool->paramcount * sizeof(typedesc);
584 pool->descriptorsize = size;
586 pool->descriptors = MNEW(u1,size);
587 pool->descriptors_next = pool->descriptors;
590 size = pool->fieldcount + pool->methodcount;
592 pool->descriptor_kind = DMNEW(u1,size);
593 pool->descriptor_kind_next = pool->descriptor_kind;
597 /* descriptor_pool_parse_field_descriptor **************************************
599 Parse the given field descriptor
602 pool.............the descriptor_pool
603 desc.............the field descriptor
606 a pointer to the parsed field descriptor, or
607 NULL if an exception has been thrown
610 descriptor_pool_alloc_parsed_descriptors must be called (once) before this
613 *******************************************************************************/
616 descriptor_pool_parse_field_descriptor(descriptor_pool *pool,utf *desc)
619 descriptor_hash_entry *c;
622 DESCRIPTOR_ASSERT(pool);
623 DESCRIPTOR_ASSERT(pool->descriptors);
624 DESCRIPTOR_ASSERT(pool->descriptors_next);
626 /* lookup the descriptor in the hashtable */
627 key = utf_hashkey(desc->text, desc->blength);
628 slot = key & (pool->descriptorhash.size - 1);
629 c = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
631 if (c->desc == desc) {
633 if (c->parseddesc.fd)
634 return c->parseddesc.fd;
640 DESCRIPTOR_ASSERT(c);
642 if (desc->text[0] == '(') {
643 *exceptionptr = new_classformaterror(pool->referer,
644 "Method descriptor used in field reference");
648 d = (typedesc *) pool->descriptors_next;
649 pool->descriptors_next += sizeof(typedesc);
651 if (!descriptor_to_typedesc(pool,desc->text,utf_end(desc),NULL,d))
654 *(pool->descriptor_kind_next++) = 'f';
656 c->parseddesc.fd = d;
660 /* descriptor_pool_parse_method_descriptor *************************************
662 Parse the given method descriptor
665 pool.............the descriptor_pool
666 desc.............the method descriptor
669 a pointer to the parsed method descriptor, or
670 NULL if an exception has been thrown
673 descriptor_pool_alloc_parsed_descriptors must be called (once) before this
676 *******************************************************************************/
679 descriptor_pool_parse_method_descriptor(descriptor_pool *pool,utf *desc)
682 descriptor_hash_entry *c;
690 DESCRIPTOR_ASSERT(pool);
691 DESCRIPTOR_ASSERT(pool->descriptors);
692 DESCRIPTOR_ASSERT(pool->descriptors_next);
694 /* lookup the descriptor in the hashtable */
695 key = utf_hashkey(desc->text, desc->blength);
696 slot = key & (pool->descriptorhash.size - 1);
697 c = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
699 if (c->desc == desc) {
701 if (c->parseddesc.md)
702 return c->parseddesc.md;
708 DESCRIPTOR_ASSERT(c);
710 md = (methoddesc *) pool->descriptors_next;
711 pool->descriptors_next += sizeof(methoddesc) - sizeof(typedesc);
713 utf_ptr = desc->text;
714 end_pos = utf_end(desc);
716 if (*utf_ptr++ != '(') {
717 *exceptionptr = new_classformaterror(pool->referer,
718 "Field descriptor used in method reference");
723 while (*utf_ptr != ')') {
724 /* parse a parameter type */
725 if (!descriptor_to_typedesc(pool,utf_ptr,end_pos,&utf_ptr,d))
728 if (d->type == TYPE_LONG || d->type == TYPE_DOUBLE)
732 pool->descriptors_next += sizeof(typedesc);
736 utf_ptr++; /* skip ')' */
738 /* parse return type */
739 if (!descriptor_to_typedesc(pool,utf_ptr,end_pos,NULL,&(md->returntype)))
742 md->paramcount = paramcount;
743 md->paramslots = paramslots;
744 *(pool->descriptor_kind_next++) = 'm';
745 c->parseddesc.md = md;
749 /* descriptor_pool_get_parsed_descriptors **************************************
751 Return a pointer to the block of parsed descriptors
754 pool.............the descriptor_pool
757 *size............if size is non-NULL, this is set to the size of the
758 parsed descriptor block (in u1)
761 a pointer to the block of parsed descriptors
764 descriptor_pool_alloc_parsed_descriptors must be called (once) before this
767 *******************************************************************************/
770 descriptor_pool_get_parsed_descriptors(descriptor_pool *pool,s4 *size)
772 DESCRIPTOR_ASSERT(pool);
773 DESCRIPTOR_ASSERT((!pool->fieldcount && !pool->methodcount) || pool->descriptors);
776 *size = pool->descriptorsize;
777 return pool->descriptors;
780 /* descriptor_pool_get_sizes ***************************************************
782 Get the sizes of the class reference table and the parsed descriptors
785 pool.............the descriptor_pool
788 *classrefsize....set to size of the class reference table
789 *descsize........set to size of the parsed descriptors
792 This function may only be called after both
793 descriptor_pool_create_classrefs, and
794 descriptor_pool_alloc_parsed_descriptors
797 *******************************************************************************/
800 descriptor_pool_get_sizes(descriptor_pool *pool,
801 u4 *classrefsize,u4 *descsize)
803 DESCRIPTOR_ASSERT(pool);
804 DESCRIPTOR_ASSERT((!pool->fieldcount && !pool->methodcount) || pool->descriptors);
805 DESCRIPTOR_ASSERT(pool->classrefs);
806 DESCRIPTOR_ASSERT(classrefsize);
807 DESCRIPTOR_ASSERT(descsize);
809 *classrefsize = pool->classrefhash.entries * sizeof(constant_classref);
810 *descsize = pool->descriptorsize;
813 /* descriptor_debug_print_typedesc *********************************************
815 Print the given typedesc to the given stream
818 file.............stream to print to
819 d................the parsed descriptor
821 *******************************************************************************/
824 descriptor_debug_print_typedesc(FILE *file,typedesc *d)
829 fprintf(file,"(typedesc *)NULL");
833 if (d->type == TYPE_ADDRESS) {
834 utf_fprint(file,d->classref->name);
837 switch (d->decltype) {
838 case PRIMITIVETYPE_INT : ch='I'; break;
839 case PRIMITIVETYPE_CHAR : ch='C'; break;
840 case PRIMITIVETYPE_BYTE : ch='B'; break;
841 case PRIMITIVETYPE_SHORT : ch='S'; break;
842 case PRIMITIVETYPE_BOOLEAN: ch='Z'; break;
843 case PRIMITIVETYPE_LONG : ch='J'; break;
844 case PRIMITIVETYPE_FLOAT : ch='F'; break;
845 case PRIMITIVETYPE_DOUBLE : ch='D'; break;
846 case PRIMITIVETYPE_VOID : ch='V'; break;
852 fprintf(file,"[%d]",d->arraydim);
855 /* descriptor_debug_print_methoddesc *******************************************
857 Print the given methoddesc to the given stream
860 file.............stream to print to
861 d................the parsed descriptor
863 *******************************************************************************/
866 descriptor_debug_print_methoddesc(FILE *file,methoddesc *d)
871 fprintf(file,"(methoddesc *)NULL");
876 for (i=0; i<d->paramcount; ++i) {
879 descriptor_debug_print_typedesc(file,d->paramtypes + i);
882 descriptor_debug_print_typedesc(file,&(d->returntype));
885 /* descriptor_pool_debug_dump **************************************************
887 Print the state of the descriptor_pool to the given stream
890 pool.............the descriptor_pool
891 file.............stream to print to
893 *******************************************************************************/
896 descriptor_pool_debug_dump(descriptor_pool *pool,FILE *file)
903 fprintf(file,"======[descriptor_pool for ");
904 utf_fprint(file,pool->referer->name);
905 fprintf(file,"]======\n");
907 fprintf(file,"fieldcount: %d\n",pool->fieldcount);
908 fprintf(file,"methodcount: %d\n",pool->methodcount);
909 fprintf(file,"paramcount: %d\n",pool->paramcount);
910 fprintf(file,"classrefcount: %d\n",pool->classrefhash.entries);
911 fprintf(file,"descriptorsize: %d bytes\n",pool->descriptorsize);
912 fprintf(file,"classrefsize: %d bytes\n",
913 (int)(pool->classrefhash.entries * sizeof(constant_classref)));
915 fprintf(file,"class references:\n");
916 for (slot=0; slot<pool->classrefhash.size; ++slot) {
917 classref_hash_entry *c = (classref_hash_entry *) pool->classrefhash.ptr[slot];
919 fprintf(file," %4d: ",c->index);
920 utf_fprint(file,c->name);
926 fprintf(file,"hashed descriptors:\n");
927 for (slot=0; slot<pool->descriptorhash.size; ++slot) {
928 descriptor_hash_entry *c = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
930 fprintf(file," %p: ",c->parseddesc.any);
931 utf_fprint(file,c->desc);
937 fprintf(file,"descriptors:\n");
938 if (pool->descriptors) {
939 pos = pool->descriptors;
940 size = pool->descriptors_next - pool->descriptors;
941 fprintf(file," size: %d bytes\n",size);
943 if (pool->descriptor_kind) {
944 kind = pool->descriptor_kind;
946 while (pos < (pool->descriptors + size)) {
947 fprintf(file," %p: ",pos);
950 descriptor_debug_print_typedesc(file,(typedesc*)pos);
951 pos += sizeof(typedesc);
954 descriptor_debug_print_methoddesc(file,(methoddesc*)pos);
955 pos += ((methoddesc*)pos)->paramcount * sizeof(typedesc);
956 pos += sizeof(methoddesc) - sizeof(typedesc);
959 fprintf(file,"INVALID KIND");
965 while (size >= sizeof(voidptr)) {
966 fprintf(file," %p\n",*((voidptr*)pos));
967 pos += sizeof(voidptr);
968 size -= sizeof(voidptr);
973 fprintf(file,"==========================================================\n");
977 * These are local overrides for various environment variables in Emacs.
978 * Please do not remove this and leave it at the end of the file, where
979 * Emacs will automagically detect them.
980 * ---------------------------------------------------------------------
983 * indent-tabs-mode: t
987 * vim:noexpandtab:sw=4:ts=4: