X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fdescriptor.c;h=c5e512d89be3f7416138abda31f41852fb86fb1f;hb=48a98d167eb6b2bb826a0317b9924fbdc8303062;hp=bfa3fea0276c272677e6d9826032389ad45a91a8;hpb=8a4b1036a251c50fe47289518c52a71f4fe5f60b;p=cacao.git diff --git a/src/vm/descriptor.c b/src/vm/descriptor.c index bfa3fea02..c5e512d89 100644 --- a/src/vm/descriptor.c +++ b/src/vm/descriptor.c @@ -1,9 +1,9 @@ -/* vm/descriptor.c - checking and parsing of field / method descriptors +/* src/vm/descriptor.c - checking and parsing of field / method descriptors - Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates, - R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, - C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, - Institut f. Computersprachen - TU Wien + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien This file is part of CACAO. @@ -19,22 +19,35 @@ 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., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. - Contact: cacao@complang.tuwien.ac.at + Contact: cacao@cacaojvm.org Authors: Edwin Steiner + Christian Thalinger + Christian Ullrich - Changes: - - $Id: descriptor.c 2075 2005-03-25 12:33:37Z edwin $ + $Id: descriptor.c 6286 2007-01-10 10:03:38Z twisti $ */ + +#include "config.h" + #include + +#include "vm/types.h" + +#include "md-abi.h" + +#include "mm/memory.h" #include "vm/descriptor.h" #include "vm/exceptions.h" +#include "vm/options.h" +#include "vm/resolve.h" +#include "vm/stringlocal.h" + /* constants (private to descriptor.c) ****************************************/ @@ -63,21 +76,128 @@ struct descriptor_hash_entry { descriptor_hash_entry *hashlink; utf *desc; parseddesc 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) + + /****************************************************************************/ /* DEBUG HELPERS */ /****************************************************************************/ -#ifndef NDEBUG -#define DESCRIPTOR_DEBUG -#endif +/*#define DESCRIPTOR_VERBOSE*/ -#ifdef DESCRIPTOR_DEBUG -#define DESCRIPTOR_ASSERT(cond) assert(cond) -#else -#define DESCRIPTOR_ASSERT(cond) -#endif +/****************************************************************************/ +/* 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 '('. + +*******************************************************************************/ + +u2 descriptor_to_basic_type(utf *descriptor) +{ + assert(descriptor->blength >= 1); + + switch (descriptor->text[0]) { + case 'B': + case 'C': + case 'I': + case 'S': + case 'Z': return TYPE_INT; + case 'D': return TYPE_DBL; + case 'F': return TYPE_FLT; + case 'J': return TYPE_LNG; + case 'L': + case '[': return TYPE_ADR; + } + + assert(0); + + return 0; /* keep the compiler happy */ +} + +/* descriptor_typesize**** **************************************************** + + Return the size in bytes needed for the given type. + + IN: + td..............typedesc describing the type + + OUT: + The number of bytes + +*******************************************************************************/ + +u2 descriptor_typesize(typedesc *td) +{ + assert(td); + + switch (td->type) { + case TYPE_INT: return 4; + case TYPE_LNG: return 8; + case TYPE_FLT: return 4; + case TYPE_DBL: return 8; + case TYPE_ADR: return sizeof(voidptr); + } + + assert(0); + + return 0; /* keep the compiler happy */ +} /* name_from_descriptor ******************************************************** @@ -127,10 +247,10 @@ name_from_descriptor(classinfo *c, char *start = utf_ptr; bool error = false; - DESCRIPTOR_ASSERT(c); - DESCRIPTOR_ASSERT(utf_ptr); - DESCRIPTOR_ASSERT(end_ptr); - DESCRIPTOR_ASSERT(name); + assert(c); + assert(utf_ptr); + assert(end_ptr); + assert(name); *name = NULL; SKIP_FIELDDESCRIPTOR_SAFE(utf_ptr, end_ptr, error); @@ -170,45 +290,7 @@ name_from_descriptor(classinfo *c, return false; } -/* primitive_type_from_char **************************************************** - - Return the primitive type corresponding to the given descriptor character - (Internally used helper function) - - IN: - ch...............the character - - RETURN VALUE: - The primitive type (a TYPE_* constant) - - NOTE: - This function assumes that the descriptor has already been checked. -*******************************************************************************/ - -static int -primitive_type_from_char(int ch) -{ - switch (ch) { - case 'B': - case 'C': - case 'I': - case 'S': - case 'Z': - return TYPE_INT; - case 'D': - return TYPE_DOUBLE; - case 'F': - return TYPE_FLOAT; - case 'J': - return TYPE_LONG; - case 'V': - return TYPE_VOID; - } - DESCRIPTOR_ASSERT(false); - return 0; /* for the compiler */ -} - /* descriptor_to_typedesc ****************************************************** Parse the given type descriptor and fill a typedesc struct @@ -230,32 +312,74 @@ primitive_type_from_char(int ch) *******************************************************************************/ static bool -descriptor_to_typedesc(descriptor_pool *pool,char *utf_ptr,char *end_pos, - char **next,typedesc *d) +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)) + if (!name_from_descriptor(pool->referer, utf_ptr, end_pos, next, 0, &name)) return false; if (name) { /* a reference type */ - d->type = TYPE_ADDRESS; - d->arraydim = 0; - for (utf_ptr=name->text; *utf_ptr == '['; ++utf_ptr) - d->arraydim++; - d->classref = descriptor_pool_lookup_classref(pool,name); - } - else { + td->type = TYPE_ADR; + td->decltype = 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 */ - d->type = primitive_type_from_char(*utf_ptr); - d->arraydim = 0; - d->classref = NULL; + switch (*utf_ptr) { + case 'B': + td->decltype = PRIMITIVETYPE_BYTE; + td->type = TYPE_INT; + break; + case 'C': + td->decltype = PRIMITIVETYPE_CHAR; + td->type = TYPE_INT; + break; + case 'S': + td->decltype = PRIMITIVETYPE_SHORT; + td->type = TYPE_INT; + break; + case 'Z': + td->decltype = PRIMITIVETYPE_BOOLEAN; + td->type = TYPE_INT; + break; + case 'I': + td->decltype = PRIMITIVETYPE_INT; + td->type = TYPE_INT; + break; + case 'D': + td->decltype = PRIMITIVETYPE_DOUBLE; + td->type = TYPE_DBL; + break; + case 'F': + td->decltype = PRIMITIVETYPE_FLOAT; + td->type = TYPE_FLT; + break; + case 'J': + td->decltype = PRIMITIVETYPE_LONG; + td->type = TYPE_LNG; + break; + case 'V': + td->decltype = 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 @@ -276,7 +400,7 @@ descriptor_pool_new(classinfo *referer) u4 slot; pool = DNEW(descriptor_pool); - DESCRIPTOR_ASSERT(pool); + assert(pool); pool->referer = referer; pool->fieldcount = 0; @@ -306,6 +430,7 @@ descriptor_pool_new(classinfo *referer) return pool; } + /* descriptor_pool_add_class *************************************************** Add the given class reference to the pool @@ -321,23 +446,41 @@ descriptor_pool_new(classinfo *referer) *******************************************************************************/ bool -descriptor_pool_add_class(descriptor_pool *pool,utf *name) +descriptor_pool_add_class(descriptor_pool *pool, utf *name) { u4 key,slot; classref_hash_entry *c; - DESCRIPTOR_ASSERT(pool); - DESCRIPTOR_ASSERT(name); + 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))) { + *exceptionptr = new_classformaterror(pool->referer, + "Invalid class name"); + return false; /* exception */ + } + + /* XXX check maximum array dimension */ + c = DNEW(classref_hash_entry); c->name = name; c->index = pool->classrefhash.entries++; @@ -347,6 +490,7 @@ descriptor_pool_add_class(descriptor_pool *pool,utf *name) return true; } + /* descriptor_pool_add ********************************************************* Check the given descriptor and add it to the pool @@ -355,6 +499,10 @@ descriptor_pool_add_class(descriptor_pool *pool,utf *name) 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 @@ -362,59 +510,83 @@ descriptor_pool_add_class(descriptor_pool *pool,utf *name) *******************************************************************************/ bool -descriptor_pool_add(descriptor_pool *pool,utf *desc) +descriptor_pool_add(descriptor_pool *pool, utf *desc, int *paramslots) { u4 key,slot; - descriptor_hash_entry *c; + descriptor_hash_entry *d; char *utf_ptr; char *end_pos; utf *name; + s4 argcount = 0; - DESCRIPTOR_ASSERT(pool); - DESCRIPTOR_ASSERT(desc); +#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); - c = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot]; - while (c) { - if (c->desc == desc) - return true; /* already stored */ - c = c->hashlink; + 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 */ - c = DNEW(descriptor_hash_entry); - c->desc = desc; - c->parseddesc.any = NULL; - c->hashlink = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot]; - pool->descriptorhash.ptr[slot] = c; + + d = DNEW(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 */ - utf_ptr = desc->text; - end_pos = utf_end(desc); + + end_pos = UTF_END(desc); if (*utf_ptr == '(') { - s4 argcount = 0; - /* a method descriptor */ + pool->methodcount++; utf_ptr++; /* check arguments */ - while (utf_ptr != end_pos && *utf_ptr != ')') { + + while ((utf_ptr != end_pos) && (*utf_ptr != ')')) { pool->paramcount++; - /* We cannot count the this argument here because + + /* 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; + argcount += 2; else argcount++; - if (!name_from_descriptor(pool->referer,utf_ptr,end_pos,&utf_ptr, - DESCRIPTOR_NOVOID,&name)) + + if (!name_from_descriptor(pool->referer, utf_ptr, end_pos, &utf_ptr, + DESCRIPTOR_NOVOID, &name)) return false; if (name) - descriptor_pool_add_class(pool,name); + if (!descriptor_pool_add_class(pool, name)) + return false; } if (utf_ptr == end_pos) { @@ -424,35 +596,44 @@ descriptor_pool_add(descriptor_pool *pool,utf *desc) utf_ptr++; /* skip ')' */ - if (!name_from_descriptor(pool->referer,utf_ptr,end_pos,NULL, - DESCRIPTOR_CHECKEND,&name)) + if (!name_from_descriptor(pool->referer, utf_ptr, end_pos, NULL, + DESCRIPTOR_CHECKEND, &name)) return false; if (name) - descriptor_pool_add_class(pool,name); + if (!descriptor_pool_add_class(pool,name)) + return false; if (argcount > 255) { *exceptionptr = new_classformaterror(pool->referer,"Too many arguments in signature"); return false; } - } - else { + + } else { /* a field descriptor */ + pool->fieldcount++; - if (!name_from_descriptor(pool->referer,utf_ptr,end_pos,NULL, - DESCRIPTOR_NOVOID - | DESCRIPTOR_CHECKEND,&name)) + if (!name_from_descriptor(pool->referer, utf_ptr, end_pos, NULL, + DESCRIPTOR_NOVOID | DESCRIPTOR_CHECKEND, + &name)) return false; if (name) - descriptor_pool_add_class(pool,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 @@ -470,35 +651,36 @@ descriptor_pool_add(descriptor_pool *pool,utf *desc) *******************************************************************************/ constant_classref * -descriptor_pool_create_classrefs(descriptor_pool *pool,s4 *count) +descriptor_pool_create_classrefs(descriptor_pool *pool, s4 *count) { u4 nclasses; u4 slot; classref_hash_entry *c; constant_classref *ref; - DESCRIPTOR_ASSERT(pool); + assert(pool); nclasses = pool->classrefhash.entries; pool->classrefs = MNEW(constant_classref,nclasses); /* fill the constant_classref structs */ - for (slot=0; slotclassrefhash.size; ++slot) { + + for (slot = 0; slot < pool->classrefhash.size; ++slot) { c = (classref_hash_entry *) pool->classrefhash.ptr[slot]; while (c) { ref = pool->classrefs + c->index; - ref->pseudo_vftbl = CLASSREF_PSEUDO_VFTBL; - ref->referer = pool->referer; - ref->name = c->name; + 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 @@ -514,29 +696,30 @@ descriptor_pool_create_classrefs(descriptor_pool *pool,s4 *count) *******************************************************************************/ constant_classref * -descriptor_pool_lookup_classref(descriptor_pool *pool,utf *classname) +descriptor_pool_lookup_classref(descriptor_pool *pool, utf *classname) { u4 key,slot; classref_hash_entry *c; - DESCRIPTOR_ASSERT(pool); - DESCRIPTOR_ASSERT(pool->classrefs); - DESCRIPTOR_ASSERT(classname); + 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; } - *exceptionptr = new_exception_message(string_java_lang_InternalError, - "Class reference not found in descriptor pool"); + exceptions_throw_internalerror("Class reference not found in descriptor pool"); return NULL; } + /* descriptor_pool_alloc_parsed_descriptors ************************************ Allocate space for the parsed descriptors @@ -555,25 +738,31 @@ descriptor_pool_alloc_parsed_descriptors(descriptor_pool *pool) { u4 size; - DESCRIPTOR_ASSERT(pool); + 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); + 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 = MNEW(u1, size); pool->descriptors_next = pool->descriptors; } size = pool->fieldcount + pool->methodcount; if (size) { - pool->descriptor_kind = DMNEW(u1,size); + pool->descriptor_kind = DMNEW(u1, size); pool->descriptor_kind_next = pool->descriptor_kind; } } + /* descriptor_pool_parse_field_descriptor ************************************** Parse the given field descriptor @@ -587,37 +776,39 @@ descriptor_pool_alloc_parsed_descriptors(descriptor_pool *pool) NULL if an exception has been thrown NOTE: - descriptor_pool_alloc_parsed_descriptors must be called (once) before this - function is used. + 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) +descriptor_pool_parse_field_descriptor(descriptor_pool *pool, utf *desc) { u4 key,slot; - descriptor_hash_entry *c; - typedesc *d; + descriptor_hash_entry *d; + typedesc *td; - DESCRIPTOR_ASSERT(pool); - DESCRIPTOR_ASSERT(pool->descriptors); - DESCRIPTOR_ASSERT(pool->descriptors_next); + 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); - c = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot]; - while (c) { - if (c->desc == desc) { + d = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot]; + + while (d) { + if (d->desc == desc) { /* found */ - if (c->parseddesc.fd) - return c->parseddesc.fd; + if (d->parseddesc.fd) + return d->parseddesc.fd; break; } - c = c->hashlink; + d = d->hashlink; } - DESCRIPTOR_ASSERT(c); + assert(d); if (desc->text[0] == '(') { *exceptionptr = new_classformaterror(pool->referer, @@ -625,101 +816,271 @@ descriptor_pool_parse_field_descriptor(descriptor_pool *pool,utf *desc) return NULL; } - d = (typedesc *) pool->descriptors_next; + td = (typedesc *) pool->descriptors_next; pool->descriptors_next += sizeof(typedesc); - if (!descriptor_to_typedesc(pool,desc->text,utf_end(desc),NULL,d)) + if (!descriptor_to_typedesc(pool, desc->text, UTF_END(desc), NULL, td)) return NULL; *(pool->descriptor_kind_next++) = 'f'; - c->parseddesc.fd = d; - return d; + 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 + 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. + 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) +descriptor_pool_parse_method_descriptor(descriptor_pool *pool, utf *desc, + s4 mflags,constant_classref *thisclass) { - u4 key,slot; - descriptor_hash_entry *c; - typedesc *d; - methoddesc *md; + u4 key, slot; + descriptor_hash_entry *d; + methoddesc *md; + typedesc *td; char *utf_ptr; char *end_pos; - s4 paramcount = 0; + s2 paramcount = 0; + s2 paramslots = 0; - DESCRIPTOR_ASSERT(pool); - DESCRIPTOR_ASSERT(pool->descriptors); - DESCRIPTOR_ASSERT(pool->descriptors_next); +#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] != '(') { + *exceptionptr = new_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); - c = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot]; - while (c) { - if (c->desc == desc) { - /* found */ - if (c->parseddesc.md) - return c->parseddesc.md; - break; - } - c = c->hashlink; + 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; } - DESCRIPTOR_ASSERT(c); - + assert(d); + md = (methoddesc *) pool->descriptors_next; pool->descriptors_next += sizeof(methoddesc) - sizeof(typedesc); - utf_ptr = desc->text; - end_pos = utf_end(desc); + utf_ptr = desc->text + 1; /* skip '(' */ + end_pos = UTF_END(desc); - if (*utf_ptr++ != '(') { - *exceptionptr = new_classformaterror(pool->referer, - "Field descriptor used in method reference"); - return NULL; + td = md->paramtypes; + + /* count the `this' pointer */ + + if ((mflags != ACC_UNDEF) && !(mflags & ACC_STATIC)) { + td->type = TYPE_ADR; + td->decltype = TYPE_ADR; + td->arraydim = 0; + td->classref = thisclass; + + td++; + pool->descriptors_next += sizeof(typedesc); + paramcount++; + paramslots++; } - d = md->paramtypes; while (*utf_ptr != ')') { /* parse a parameter type */ - if (!descriptor_to_typedesc(pool,utf_ptr,end_pos,&utf_ptr,d)) + + if (!descriptor_to_typedesc(pool, utf_ptr, end_pos, &utf_ptr, td)) return NULL; + + if (IS_2_WORD_TYPE(td->type)) + paramslots++; - d++; + 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; + + if (!descriptor_to_typedesc(pool, utf_ptr, end_pos, NULL, + &(md->returntype))) + return NULL; md->paramcount = paramcount; + md->paramslots = paramslots; + + /* If m != 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 + 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'; - c->parseddesc.md = md; + + 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. + + RETURN VALUE: + true.............the paramdescs were created successfully + false............an exception has been thrown + + POSTCONDITION: + md->parms != NULL + +*******************************************************************************/ + +bool 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->decltype = 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 + md_param_alloc(md); +#endif + + return true; +} + + /* descriptor_pool_get_parsed_descriptors ************************************** Return a pointer to the block of parsed descriptors @@ -735,22 +1096,24 @@ descriptor_pool_parse_method_descriptor(descriptor_pool *pool,utf *desc) a pointer to the block of parsed descriptors NOTE: - descriptor_pool_alloc_parsed_descriptors must be called (once) before this - function is used. + descriptor_pool_alloc_parsed_descriptors must be called (once) + before this function is used. *******************************************************************************/ void * -descriptor_pool_get_parsed_descriptors(descriptor_pool *pool,s4 *size) +descriptor_pool_get_parsed_descriptors(descriptor_pool *pool, s4 *size) { - DESCRIPTOR_ASSERT(pool); - DESCRIPTOR_ASSERT((!pool->fieldcount && !pool->methodcount) || pool->descriptors); + assert(pool); + assert((!pool->fieldcount && !pool->methodcount) || pool->descriptors); if (size) *size = pool->descriptorsize; + return pool->descriptors; } + /* descriptor_pool_get_sizes *************************************************** Get the sizes of the class reference table and the parsed descriptors @@ -771,19 +1134,24 @@ descriptor_pool_get_parsed_descriptors(descriptor_pool *pool,s4 *size) *******************************************************************************/ void -descriptor_pool_get_sizes(descriptor_pool *pool, - u4 *classrefsize,u4 *descsize) +descriptor_pool_get_sizes(descriptor_pool *pool, u4 *classrefsize, u4 *descsize) { - DESCRIPTOR_ASSERT(pool); - DESCRIPTOR_ASSERT((!pool->fieldcount && !pool->methodcount) || pool->descriptors); - DESCRIPTOR_ASSERT(pool->classrefs); - DESCRIPTOR_ASSERT(classrefsize); - DESCRIPTOR_ASSERT(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 @@ -804,18 +1172,24 @@ descriptor_debug_print_typedesc(FILE *file,typedesc *d) return; } - if (d->type == TYPE_ADDRESS) { - utf_fprint(file,d->classref->name); + if (d->type == TYPE_ADR) { + if (d->classref) + utf_fprint_printable_ascii(file,d->classref->name); + else + fprintf(file,""); } else { - switch (d->type) { - case TYPE_INT : ch='I'; break; - case TYPE_LONG : ch='J'; break; - case TYPE_FLOAT : ch='F'; break; - case TYPE_DOUBLE : ch='D'; break; - case TYPE_ADDRESS: ch='A'; break; - case TYPE_VOID : ch='V'; break; - default : ch='!'; + switch (d->decltype) { + 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); } @@ -823,6 +1197,32 @@ descriptor_debug_print_typedesc(FILE *file,typedesc *d) 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 @@ -848,7 +1248,12 @@ descriptor_debug_print_methoddesc(FILE *file,methoddesc *d) 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)); } @@ -872,7 +1277,7 @@ descriptor_pool_debug_dump(descriptor_pool *pool,FILE *file) u4 size; fprintf(file,"======[descriptor_pool for "); - utf_fprint(file,pool->referer->name); + utf_fprint_printable_ascii(file,pool->referer->name); fprintf(file,"]======\n"); fprintf(file,"fieldcount: %d\n",pool->fieldcount); @@ -881,14 +1286,14 @@ descriptor_pool_debug_dump(descriptor_pool *pool,FILE *file) fprintf(file,"classrefcount: %d\n",pool->classrefhash.entries); fprintf(file,"descriptorsize: %d bytes\n",pool->descriptorsize); fprintf(file,"classrefsize: %d bytes\n", - pool->classrefhash.entries * sizeof(constant_classref)); + (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(file,c->name); + utf_fprint_printable_ascii(file,c->name); fprintf(file,"\n"); c = c->hashlink; } @@ -899,7 +1304,7 @@ descriptor_pool_debug_dump(descriptor_pool *pool,FILE *file) descriptor_hash_entry *c = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot]; while (c) { fprintf(file," %p: ",c->parseddesc.any); - utf_fprint(file,c->desc); + utf_fprint_printable_ascii(file,c->desc); fprintf(file,"\n"); c = c->hashlink; } @@ -943,6 +1348,7 @@ descriptor_pool_debug_dump(descriptor_pool *pool,FILE *file) fprintf(file,"==========================================================\n"); } +#endif /* !defined(NDEBUG) */ /* * These are local overrides for various environment variables in Emacs.