/* src/vm/descriptor.c - checking and parsing of field / method descriptors Copyright (C) 1996-2011 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #include #include "vm/types.h" #include "md-abi.h" #include "mm/memory.hpp" #include "vm/descriptor.hpp" #include "vm/exceptions.hpp" #include "vm/options.h" #include "vm/primitive.hpp" #include "vm/vm.hpp" #include "vm/jit/abi.h" /* constants (private to descriptor.c) ****************************************/ /* initial number of entries for the classrefhash of a descriptor_pool */ /* (currently the hash is never grown!) */ #define CLASSREFHASH_INIT_SIZE 64 /* initial number of entries for the descriptorhash of a descriptor_pool */ /* (currently the hash is never grown!) */ #define DESCRIPTORHASH_INIT_SIZE 128 /* data structures (private to descriptor.c) **********************************/ typedef struct classref_hash_entry classref_hash_entry; typedef struct descriptor_hash_entry descriptor_hash_entry; /* entry struct for the classrefhash of descriptor_pool */ struct classref_hash_entry { classref_hash_entry *hashlink; /* for hash chaining */ utf *name; /* name of the class refered to */ u2 index; /* index into classref table */ }; /* entry struct for the descriptorhash of descriptor_pool */ struct descriptor_hash_entry { descriptor_hash_entry *hashlink; utf *desc; parseddesc_t parseddesc; s2 paramslots; /* number of params, LONG/DOUBLE counted as 2 */ }; /****************************************************************************/ /* MACROS FOR DESCRIPTOR PARSING (private to descriptor.c) */ /****************************************************************************/ /* SKIP_FIELDDESCRIPTOR: * utf_ptr must point to the first character of a field descriptor. * After the macro call utf_ptr points to the first character after * the field descriptor. * * CAUTION: This macro does not check for an unexpected end of the * descriptor. Better use SKIP_FIELDDESCRIPTOR_SAFE. */ #define SKIP_FIELDDESCRIPTOR(utf_ptr) \ do { while (*(utf_ptr)=='[') (utf_ptr)++; \ if (*(utf_ptr)++=='L') \ while(*(utf_ptr)++ != ';') /* skip */; } while(0) /* SKIP_FIELDDESCRIPTOR_SAFE: * utf_ptr must point to the first character of a field descriptor. * After the macro call utf_ptr points to the first character after * the field descriptor. * * Input: * utf_ptr....points to first char of descriptor * end_ptr....points to first char after the end of the string * errorflag..must be initialized (to false) by the caller! * Output: * utf_ptr....points to first char after the descriptor * errorflag..set to true if the string ended unexpectedly */ #define SKIP_FIELDDESCRIPTOR_SAFE(utf_ptr,end_ptr,errorflag) \ do { while ((utf_ptr) != (end_ptr) && *(utf_ptr)=='[') (utf_ptr)++; \ if ((utf_ptr) == (end_ptr)) \ (errorflag) = true; \ else \ if (*(utf_ptr)++=='L') { \ while((utf_ptr) != (end_ptr) && *(utf_ptr)++ != ';') \ /* skip */; \ if ((utf_ptr)[-1] != ';') \ (errorflag) = true; }} while(0) #if defined(__cplusplus) extern "C" { #endif /****************************************************************************/ /* DEBUG HELPERS */ /****************************************************************************/ /*#define DESCRIPTOR_VERBOSE*/ /****************************************************************************/ /* FUNCTIONS */ /****************************************************************************/ /* descriptor_to_basic_type **************************************************** Return the basic type to use for a value with this descriptor. IN: utf..............descriptor utf string OUT: A TYPE_* constant. PRECONDITIONS: This function assumes that the descriptor has passed descriptor_pool_add checks and that it does not start with '('. *******************************************************************************/ int descriptor_to_basic_type(utf *descriptor) { assert(descriptor->blength >= 1); switch (descriptor->text[0]) { case 'Z': case 'B': case 'C': case 'S': case 'I': return TYPE_INT; case 'J': return TYPE_LNG; case 'F': return TYPE_FLT; case 'D': return TYPE_DBL; case 'L': case '[': return TYPE_ADR; default: vm_abort("descriptor_to_basic_type: invalid type %c", descriptor->text[0]); } /* keep the compiler happy */ return 0; } /* descriptor_typesize ********************************************************* Return the size in bytes needed for the given type. IN: td..............typedesc describing the type OUT: The number of bytes *******************************************************************************/ int descriptor_typesize(typedesc *td) { assert(td); switch (td->type) { case TYPE_INT: case TYPE_FLT: return 4; case TYPE_LNG: case TYPE_DBL: return 8; case TYPE_ADR: return SIZEOF_VOID_P; default: vm_abort("descriptor_typesize: invalid type %d", td->type); } /* keep the compiler happy */ return 0; } /* name_from_descriptor ******************************************************** Return the class name indicated by the given descriptor (Internally used helper function) IN: c................class containing the descriptor utf_ptr..........first character of descriptor end_ptr..........first character after the end of the string mode.............a combination (binary or) of the following flags: (Flags marked with * are the default settings.) How to handle "V" descriptors: * DESCRIPTOR_VOID.....handle it like other primitive types DESCRIPTOR_NOVOID...treat it as an error How to deal with extra characters after the end of the descriptor: * DESCRIPTOR_NOCHECKEND...ignore (useful for parameter lists) DESCRIPTOR_CHECKEND.....treat them as an error OUT: *next............if non-NULL, *next is set to the first character after the descriptor. (Undefined if an error occurs.) *name............set to the utf name of the class RETURN VALUE: true.............descriptor parsed successfully false............an exception has been thrown *******************************************************************************/ #define DESCRIPTOR_VOID 0 /* default */ #define DESCRIPTOR_NOVOID 0x0040 #define DESCRIPTOR_NOCHECKEND 0 /* default */ #define DESCRIPTOR_CHECKEND 0x1000 static bool name_from_descriptor(classinfo *c, char *utf_ptr, char *end_ptr, char **next, int mode, utf **name) { char *start = utf_ptr; bool error = false; assert(c); assert(utf_ptr); assert(end_ptr); assert(name); *name = NULL; SKIP_FIELDDESCRIPTOR_SAFE(utf_ptr, end_ptr, error); if (mode & DESCRIPTOR_CHECKEND) error |= (utf_ptr != end_ptr); if (!error) { if (next) *next = utf_ptr; switch (*start) { case 'V': if (mode & DESCRIPTOR_NOVOID) break; /* FALLTHROUGH! */ case 'I': case 'J': case 'F': case 'D': case 'B': case 'C': case 'S': case 'Z': return true; case 'L': start++; utf_ptr--; /* FALLTHROUGH! */ case '[': *name = utf_new(start, utf_ptr - start); return true; } } exceptions_throw_classformaterror(c, "Invalid descriptor"); return false; } /* descriptor_to_typedesc ****************************************************** Parse the given type descriptor and fill a typedesc struct (Internally used helper function) IN: pool.............the descriptor pool utf_ptr..........points to first character of type descriptor end_pos..........points after last character of the whole descriptor OUT: *next............set to next character after type descriptor *d...............filled with parsed information RETURN VALUE: true.............parsing succeeded false............an exception has been thrown *******************************************************************************/ static bool descriptor_to_typedesc(descriptor_pool *pool, char *utf_ptr, char *end_pos, char **next, typedesc *td) { utf *name; if (!name_from_descriptor(pool->referer, utf_ptr, end_pos, next, 0, &name)) return false; if (name) { /* a reference type */ td->type = TYPE_ADR; td->primitivetype = TYPE_ADR; td->arraydim = 0; for (utf_ptr = name->text; *utf_ptr == '['; ++utf_ptr) td->arraydim++; td->classref = descriptor_pool_lookup_classref(pool, name); } else { /* a primitive type */ switch (*utf_ptr) { case 'B': td->primitivetype = PRIMITIVETYPE_BYTE; td->type = TYPE_INT; break; case 'C': td->primitivetype = PRIMITIVETYPE_CHAR; td->type = TYPE_INT; break; case 'S': td->primitivetype = PRIMITIVETYPE_SHORT; td->type = TYPE_INT; break; case 'Z': td->primitivetype = PRIMITIVETYPE_BOOLEAN; td->type = TYPE_INT; break; case 'I': td->primitivetype = PRIMITIVETYPE_INT; td->type = TYPE_INT; break; case 'D': td->primitivetype = PRIMITIVETYPE_DOUBLE; td->type = TYPE_DBL; break; case 'F': td->primitivetype = PRIMITIVETYPE_FLOAT; td->type = TYPE_FLT; break; case 'J': td->primitivetype = PRIMITIVETYPE_LONG; td->type = TYPE_LNG; break; case 'V': td->primitivetype = PRIMITIVETYPE_VOID; td->type = TYPE_VOID; break; default: assert(false); } td->arraydim = 0; td->classref = NULL; } return true; } /* descriptor_pool_new ********************************************************* Allocate a new descriptor_pool IN: referer..........class for which to create the pool RETURN VALUE: a pointer to the new descriptor_pool *******************************************************************************/ descriptor_pool * descriptor_pool_new(classinfo *referer) { descriptor_pool *pool; u4 hashsize; u4 slot; pool = (descriptor_pool*) DumpMemory::allocate(sizeof(descriptor_pool)); assert(pool); pool->referer = referer; pool->fieldcount = 0; pool->methodcount = 0; pool->paramcount = 0; pool->descriptorsize = 0; pool->descriptors = NULL; pool->descriptors_next = NULL; pool->classrefs = NULL; pool->descriptor_kind = NULL; pool->descriptor_kind_next = NULL; hashsize = CLASSREFHASH_INIT_SIZE; pool->classrefhash.size = hashsize; pool->classrefhash.entries = 0; pool->classrefhash.ptr = (void **) DumpMemory::allocate(sizeof(void*) * hashsize); for (slot=0; slotclassrefhash.ptr[slot] = NULL; hashsize = DESCRIPTORHASH_INIT_SIZE; pool->descriptorhash.size = hashsize; pool->descriptorhash.entries = 0; pool->descriptorhash.ptr = (void**) DumpMemory::allocate(sizeof(void*) * hashsize); for (slot=0; slotdescriptorhash.ptr[slot] = NULL; return pool; } /* descriptor_pool_add_class *************************************************** Add the given class reference to the pool IN: pool.............the descriptor_pool name.............the class reference to add RETURN VALUE: true.............reference has been added false............an exception has been thrown *******************************************************************************/ bool descriptor_pool_add_class(descriptor_pool *pool, utf *name) { u4 key,slot; classref_hash_entry *c; assert(pool); assert(name); #ifdef DESCRIPTOR_VERBOSE fprintf(stderr,"descriptor_pool_add_class(%p,",(void*)pool); utf_fprint_printable_ascii(stderr,name);fprintf(stderr,")\n"); #endif /* find a place in the hashtable */ key = utf_hashkey(name->text, name->blength); slot = key & (pool->classrefhash.size - 1); c = (classref_hash_entry *) pool->classrefhash.ptr[slot]; while (c) { if (c->name == name) return true; /* already stored */ c = c->hashlink; } /* check if the name is a valid classname */ if (!is_valid_name(name->text,UTF_END(name))) { exceptions_throw_classformaterror(pool->referer, "Invalid class name"); return false; /* exception */ } /* XXX check maximum array dimension */ c = (classref_hash_entry*) DumpMemory::allocate(sizeof(classref_hash_entry)); c->name = name; c->index = pool->classrefhash.entries++; c->hashlink = (classref_hash_entry *) pool->classrefhash.ptr[slot]; pool->classrefhash.ptr[slot] = c; return true; } /* descriptor_pool_add ********************************************************* Check the given descriptor and add it to the pool IN: pool.............the descriptor_pool desc.............the descriptor to add. Maybe a field or method desc. OUT: *paramslots......if non-NULL, set to the number of parameters. LONG and DOUBLE are counted twice RETURN VALUE: true.............descriptor has been added false............an exception has been thrown *******************************************************************************/ bool descriptor_pool_add(descriptor_pool *pool, utf *desc, int *paramslots) { u4 key,slot; descriptor_hash_entry *d; char *utf_ptr; char *end_pos; utf *name; s4 argcount = 0; #ifdef DESCRIPTOR_VERBOSE fprintf(stderr,"descriptor_pool_add(%p,",(void*)pool); utf_fprint_printable_ascii(stderr,desc);fprintf(stderr,")\n"); #endif assert(pool); assert(desc); /* find a place in the hashtable */ key = utf_hashkey(desc->text, desc->blength); slot = key & (pool->descriptorhash.size - 1); d = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot]; /* Save all method descriptors in the hashtable, since the parsed */ /* descriptor may vary between differenf methods (static vs. non-static). */ utf_ptr = desc->text; if (*utf_ptr != '(') { while (d) { if (d->desc == desc) { if (paramslots) *paramslots = d->paramslots; return true; /* already stored */ } d = d->hashlink; } } /* add the descriptor to the pool */ d = (descriptor_hash_entry*) DumpMemory::allocate(sizeof(descriptor_hash_entry)); d->desc = desc; d->parseddesc.any = NULL; d->hashlink = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot]; pool->descriptorhash.ptr[slot] = d; /* now check the descriptor */ end_pos = UTF_END(desc); if (*utf_ptr == '(') { /* a method descriptor */ pool->methodcount++; utf_ptr++; /* check arguments */ while ((utf_ptr != end_pos) && (*utf_ptr != ')')) { pool->paramcount++; /* We cannot count the `this' argument here because * we don't know if the method is static. */ if (*utf_ptr == 'J' || *utf_ptr == 'D') argcount += 2; else argcount++; if (!name_from_descriptor(pool->referer, utf_ptr, end_pos, &utf_ptr, DESCRIPTOR_NOVOID, &name)) return false; if (name) if (!descriptor_pool_add_class(pool, name)) return false; } if (utf_ptr == end_pos) { exceptions_throw_classformaterror(pool->referer, "Missing ')' in method descriptor"); return false; } utf_ptr++; /* skip ')' */ if (!name_from_descriptor(pool->referer, utf_ptr, end_pos, NULL, DESCRIPTOR_CHECKEND, &name)) return false; if (name) if (!descriptor_pool_add_class(pool,name)) return false; if (argcount > 255) { exceptions_throw_classformaterror(pool->referer, "Too many arguments in signature"); return false; } } else { /* a field descriptor */ pool->fieldcount++; if (!name_from_descriptor(pool->referer, utf_ptr, end_pos, NULL, DESCRIPTOR_NOVOID | DESCRIPTOR_CHECKEND, &name)) return false; if (name) if (!descriptor_pool_add_class(pool,name)) return false; } d->paramslots = argcount; if (paramslots) *paramslots = argcount; return true; } /* descriptor_pool_create_classrefs ******************************************** Create a table containing all the classrefs which were added to the pool IN: pool.............the descriptor_pool OUT: *count...........if count is non-NULL, this is set to the number of classrefs in the table RETURN VALUE: a pointer to the constant_classref table *******************************************************************************/ constant_classref * descriptor_pool_create_classrefs(descriptor_pool *pool, s4 *count) { u4 nclasses; u4 slot; classref_hash_entry *c; constant_classref *ref; assert(pool); nclasses = pool->classrefhash.entries; pool->classrefs = MNEW(constant_classref,nclasses); /* fill the constant_classref structs */ for (slot = 0; slot < pool->classrefhash.size; ++slot) { c = (classref_hash_entry *) pool->classrefhash.ptr[slot]; while (c) { ref = pool->classrefs + c->index; CLASSREF_INIT(*ref, pool->referer, c->name); c = c->hashlink; } } if (count) *count = nclasses; return pool->classrefs; } /* descriptor_pool_lookup_classref ********************************************* Return the constant_classref for the given class name IN: pool.............the descriptor_pool classname........name of the class to look up RETURN VALUE: a pointer to the constant_classref, or NULL if an exception has been thrown *******************************************************************************/ constant_classref * descriptor_pool_lookup_classref(descriptor_pool *pool, utf *classname) { u4 key,slot; classref_hash_entry *c; assert(pool); assert(pool->classrefs); assert(classname); key = utf_hashkey(classname->text, classname->blength); slot = key & (pool->classrefhash.size - 1); c = (classref_hash_entry *) pool->classrefhash.ptr[slot]; while (c) { if (c->name == classname) return pool->classrefs + c->index; c = c->hashlink; } exceptions_throw_internalerror("Class reference not found in descriptor pool"); return NULL; } /* descriptor_pool_alloc_parsed_descriptors ************************************ Allocate space for the parsed descriptors IN: pool.............the descriptor_pool NOTE: This function must be called after all descriptors have been added with descriptor_pool_add. *******************************************************************************/ void descriptor_pool_alloc_parsed_descriptors(descriptor_pool *pool) { u4 size; assert(pool); /* TWISTI: paramcount + 1: we don't know if the method is static or */ /* not, i have no better solution yet. */ size = pool->fieldcount * sizeof(typedesc) + pool->methodcount * (sizeof(methoddesc) - sizeof(typedesc)) + pool->paramcount * sizeof(typedesc) + pool->methodcount * sizeof(typedesc); /* possible `this' pointer */ pool->descriptorsize = size; if (size) { pool->descriptors = MNEW(u1, size); pool->descriptors_next = pool->descriptors; } size = pool->fieldcount + pool->methodcount; if (size) { pool->descriptor_kind = (u1*) DumpMemory::allocate(sizeof(u1) * size); pool->descriptor_kind_next = pool->descriptor_kind; } } /* descriptor_pool_parse_field_descriptor ************************************** Parse the given field descriptor IN: pool.............the descriptor_pool desc.............the field descriptor RETURN VALUE: a pointer to the parsed field descriptor, or NULL if an exception has been thrown NOTE: descriptor_pool_alloc_parsed_descriptors must be called (once) before this function is used. *******************************************************************************/ typedesc * descriptor_pool_parse_field_descriptor(descriptor_pool *pool, utf *desc) { u4 key,slot; descriptor_hash_entry *d; typedesc *td; assert(pool); assert(pool->descriptors); assert(pool->descriptors_next); /* lookup the descriptor in the hashtable */ key = utf_hashkey(desc->text, desc->blength); slot = key & (pool->descriptorhash.size - 1); d = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot]; while (d) { if (d->desc == desc) { /* found */ if (d->parseddesc.fd) return d->parseddesc.fd; break; } d = d->hashlink; } assert(d); if (desc->text[0] == '(') { exceptions_throw_classformaterror(pool->referer, "Method descriptor used in field reference"); return NULL; } td = (typedesc *) pool->descriptors_next; pool->descriptors_next += sizeof(typedesc); if (!descriptor_to_typedesc(pool, desc->text, UTF_END(desc), NULL, td)) return NULL; *(pool->descriptor_kind_next++) = 'f'; d->parseddesc.fd = td; return td; } /* descriptor_pool_parse_method_descriptor ************************************* Parse the given method descriptor IN: pool.............the descriptor_pool desc.............the method descriptor mflags...........the method flags thisclass........classref to the class containing the method. This is ignored if mflags contains ACC_STATIC. The classref is stored for inserting the 'this' argument. RETURN VALUE: a pointer to the parsed method descriptor, or NULL if an exception has been thrown NOTE: descriptor_pool_alloc_parsed_descriptors must be called (once) before this function is used. *******************************************************************************/ methoddesc * descriptor_pool_parse_method_descriptor(descriptor_pool *pool, utf *desc, s4 mflags,constant_classref *thisclass) { u4 key, slot; descriptor_hash_entry *d; methoddesc *md; typedesc *td; char *utf_ptr; char *end_pos; s2 paramcount = 0; s2 paramslots = 0; #ifdef DESCRIPTOR_VERBOSE fprintf(stderr,"descriptor_pool_parse_method_descriptor(%p,%d,%p,", (void*)pool,(int)mflags,(void*)thisclass); utf_fprint_printable_ascii(stderr,desc); fprintf(stderr,")\n"); #endif assert(pool); assert(pool->descriptors); assert(pool->descriptors_next); /* check that it is a method descriptor */ if (desc->text[0] != '(') { exceptions_throw_classformaterror(pool->referer, "Field descriptor used in method reference"); return NULL; } /* lookup the descriptor in the hashtable */ key = utf_hashkey(desc->text, desc->blength); slot = key & (pool->descriptorhash.size - 1); d = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot]; /* find an un-parsed descriptor */ while (d) { if (d->desc == desc) if (!d->parseddesc.md) break; d = d->hashlink; } assert(d); md = (methoddesc *) pool->descriptors_next; pool->descriptors_next += sizeof(methoddesc) - sizeof(typedesc); utf_ptr = desc->text + 1; /* skip '(' */ end_pos = UTF_END(desc); td = md->paramtypes; /* count the `this' pointer */ if ((mflags != ACC_UNDEF) && !(mflags & ACC_STATIC)) { td->type = TYPE_ADR; td->primitivetype = TYPE_ADR; td->arraydim = 0; td->classref = thisclass; td++; pool->descriptors_next += sizeof(typedesc); paramcount++; paramslots++; } while (*utf_ptr != ')') { /* parse a parameter type */ if (!descriptor_to_typedesc(pool, utf_ptr, end_pos, &utf_ptr, td)) return NULL; if (IS_2_WORD_TYPE(td->type)) paramslots++; td++; pool->descriptors_next += sizeof(typedesc); paramcount++; paramslots++; } utf_ptr++; /* skip ')' */ /* Skip possible `this' pointer in paramtypes array to allow a possible */ /* memory move later in parse. */ /* We store the thisclass reference, so we can later correctly fill in */ /* the parameter slot of the 'this' argument. */ if (mflags == ACC_UNDEF) { td->classref = thisclass; td++; pool->descriptors_next += sizeof(typedesc); } /* parse return type */ if (!descriptor_to_typedesc(pool, utf_ptr, end_pos, NULL, &(md->returntype))) return NULL; md->paramcount = paramcount; md->paramslots = paramslots; /* If mflags != ACC_UNDEF we parse a real loaded method, so do param prealloc. Otherwise we do this in stack analysis. */ if (mflags != ACC_UNDEF) { if (md->paramcount > 0) { /* allocate memory for params */ md->params = MNEW(paramdesc, md->paramcount); } else { md->params = METHODDESC_NOPARAMS; } /* fill the paramdesc */ /* md_param_alloc has to be called if md->paramcount == 0, too, so it can make the reservation for the Linkage Area, Return Register... */ #if defined(ENABLE_JIT) # if defined(ENABLE_INTRP) if (!opt_intrp) # endif { /* As builtin-functions are native functions, we have to pre-allocate for the native ABI. */ if (mflags & ACC_METHOD_BUILTIN) md_param_alloc_native(md); else md_param_alloc(md); } #endif } else { /* params will be allocated later by descriptor_params_from_paramtypes if necessary */ md->params = NULL; } *(pool->descriptor_kind_next++) = 'm'; d->parseddesc.md = md; return md; } /* descriptor_params_from_paramtypes ******************************************* Create the paramdescs for a method descriptor. This function is called when we know whether the method is static or not. This function may only be called once for each methoddesc, and only if md->params == NULL. IN: md...............the parsed method descriptor md->params MUST be NULL. mflags...........the ACC_* access flags of the method. Only the ACC_STATIC bit is checked. The value ACC_UNDEF is NOT allowed. POSTCONDITION: md->parms != NULL *******************************************************************************/ void descriptor_params_from_paramtypes(methoddesc *md, s4 mflags) { typedesc *td; assert(md); assert(md->params == NULL); assert(mflags != ACC_UNDEF); td = md->paramtypes; /* check for `this' pointer */ if (!(mflags & ACC_STATIC)) { constant_classref *thisclass; /* fetch class reference from reserved param slot */ thisclass = td[md->paramcount].classref; assert(thisclass); if (md->paramcount > 0) { /* shift param types by 1 argument */ MMOVE(td + 1, td, typedesc, md->paramcount); } /* fill in first argument `this' */ td->type = TYPE_ADR; td->primitivetype = TYPE_ADR; td->arraydim = 0; td->classref = thisclass; md->paramcount++; md->paramslots++; } /* if the method has params, process them */ if (md->paramcount > 0) { /* allocate memory for params */ md->params = MNEW(paramdesc, md->paramcount); } else { md->params = METHODDESC_NOPARAMS; } /* fill the paramdesc */ /* md_param_alloc has to be called if md->paramcount == 0, too, so it can make the reservation for the Linkage Area, Return Register.. */ #if defined(ENABLE_JIT) # if defined(ENABLE_INTRP) if (!opt_intrp) # endif { /* As builtin-functions are native functions, we have to pre-allocate for the native ABI. */ if (mflags & ACC_METHOD_BUILTIN) md_param_alloc_native(md); else md_param_alloc(md); } #endif } /* descriptor_pool_get_sizes *************************************************** Get the sizes of the class reference table and the parsed descriptors IN: pool.............the descriptor_pool OUT: *classrefsize....set to size of the class reference table *descsize........set to size of the parsed descriptors NOTE: This function may only be called after both descriptor_pool_create_classrefs, and descriptor_pool_alloc_parsed_descriptors have been called. *******************************************************************************/ void descriptor_pool_get_sizes(descriptor_pool *pool, u4 *classrefsize, u4 *descsize) { assert(pool); assert((!pool->fieldcount && !pool->methodcount) || pool->descriptors); assert(pool->classrefs); assert(classrefsize); assert(descsize); *classrefsize = pool->classrefhash.entries * sizeof(constant_classref); *descsize = pool->descriptorsize; } /****************************************************************************/ /* DEBUG HELPERS */ /****************************************************************************/ #ifndef NDEBUG /* descriptor_debug_print_typedesc ********************************************* Print the given typedesc to the given stream IN: file.............stream to print to d................the parsed descriptor *******************************************************************************/ void descriptor_debug_print_typedesc(FILE *file,typedesc *d) { int ch; if (!d) { fprintf(file,"(typedesc *)NULL"); return; } if (d->type == TYPE_ADR) { if (d->classref) utf_fprint_printable_ascii(file,d->classref->name); else fprintf(file,""); } else { switch (d->primitivetype) { case PRIMITIVETYPE_INT : ch='I'; break; case PRIMITIVETYPE_CHAR : ch='C'; break; case PRIMITIVETYPE_BYTE : ch='B'; break; case PRIMITIVETYPE_SHORT : ch='S'; break; case PRIMITIVETYPE_BOOLEAN: ch='Z'; break; case PRIMITIVETYPE_LONG : ch='J'; break; case PRIMITIVETYPE_FLOAT : ch='F'; break; case PRIMITIVETYPE_DOUBLE : ch='D'; break; case PRIMITIVETYPE_VOID : ch='V'; break; default : ch='!'; } fputc(ch,file); } if (d->arraydim) fprintf(file,"[%d]",d->arraydim); } /* descriptor_debug_print_paramdesc ******************************************** Print the given paramdesc to the given stream IN: file.............stream to print to d................the parameter descriptor *******************************************************************************/ void descriptor_debug_print_paramdesc(FILE *file,paramdesc *d) { if (!d) { fprintf(file,"(paramdesc *)NULL"); return; } if (d->inmemory) { fprintf(file,"",d->regoff); } else { fprintf(file,"",d->regoff); } } /* descriptor_debug_print_methoddesc ******************************************* Print the given methoddesc to the given stream IN: file.............stream to print to d................the parsed descriptor *******************************************************************************/ void descriptor_debug_print_methoddesc(FILE *file,methoddesc *d) { int i; if (!d) { fprintf(file,"(methoddesc *)NULL"); return; } fputc('(',file); for (i=0; iparamcount; ++i) { if (i) fputc(',',file); descriptor_debug_print_typedesc(file,d->paramtypes + i); if (d->params) { descriptor_debug_print_paramdesc(file,d->params + i); } } if (d->params == METHODDESC_NOPARAMS) fputs("",file); fputc(')',file); descriptor_debug_print_typedesc(file,&(d->returntype)); } /* descriptor_pool_debug_dump ************************************************** Print the state of the descriptor_pool to the given stream IN: pool.............the descriptor_pool file.............stream to print to *******************************************************************************/ void descriptor_pool_debug_dump(descriptor_pool *pool,FILE *file) { u4 slot; u1 *pos; u1 *kind; u4 size; fprintf(file,"======[descriptor_pool for "); utf_fprint_printable_ascii(file,pool->referer->name); fprintf(file,"]======\n"); fprintf(file,"fieldcount: %d\n",pool->fieldcount); fprintf(file,"methodcount: %d\n",pool->methodcount); fprintf(file,"paramcount: %d\n",pool->paramcount); fprintf(file,"classrefcount: %d\n",pool->classrefhash.entries); fprintf(file,"descriptorsize: %d bytes\n",pool->descriptorsize); fprintf(file,"classrefsize: %d bytes\n", (int)(pool->classrefhash.entries * sizeof(constant_classref))); fprintf(file,"class references:\n"); for (slot=0; slotclassrefhash.size; ++slot) { classref_hash_entry *c = (classref_hash_entry *) pool->classrefhash.ptr[slot]; while (c) { fprintf(file," %4d: ",c->index); utf_fprint_printable_ascii(file,c->name); fprintf(file,"\n"); c = c->hashlink; } } fprintf(file,"hashed descriptors:\n"); for (slot=0; slotdescriptorhash.size; ++slot) { descriptor_hash_entry *c = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot]; while (c) { fprintf(file," %p: ",c->parseddesc.any); utf_fprint_printable_ascii(file,c->desc); fprintf(file,"\n"); c = c->hashlink; } } fprintf(file,"descriptors:\n"); if (pool->descriptors) { pos = pool->descriptors; size = pool->descriptors_next - pool->descriptors; fprintf(file," size: %d bytes\n",size); if (pool->descriptor_kind) { kind = pool->descriptor_kind; while (pos < (pool->descriptors + size)) { fprintf(file," %p: ",pos); switch (*kind++) { case 'f': descriptor_debug_print_typedesc(file,(typedesc*)pos); pos += sizeof(typedesc); break; case 'm': descriptor_debug_print_methoddesc(file,(methoddesc*)pos); pos += ((methoddesc*)pos)->paramcount * sizeof(typedesc); pos += sizeof(methoddesc) - sizeof(typedesc); break; default: fprintf(file,"INVALID KIND"); } fputc('\n',file); } } else { while (size >= sizeof(void*)) { fprintf(file," %p\n",*((void**)pos)); pos += sizeof(void*); size -= sizeof(void*); } } } fprintf(file,"==========================================================\n"); } #endif /* !defined(NDEBUG) */ #if defined(__cplusplus) } #endif /* * These are local overrides for various environment variables in Emacs. * Please do not remove this and leave it at the end of the file, where * Emacs will automagically detect them. * --------------------------------------------------------------------- * Local variables: * mode: c * indent-tabs-mode: t * c-basic-offset: 4 * tab-width: 4 * End: * vim:noexpandtab:sw=4:ts=4: */