-/* 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, 2008
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
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
+*/
- Authors: Edwin Steiner
- Changes:
+#include "config.h"
- $Id: descriptor.c 2094 2005-03-27 15:17:46Z edwin $
+#include <assert.h>
-*/
+#include "vm/types.h"
+
+#include "md-abi.h"
+
+#include "mm/memory.h"
-#include <assert.h>
#include "vm/descriptor.h"
-#include "vm/exceptions.h"
+#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) ****************************************/
/* (currently the hash is never grown!) */
#define DESCRIPTORHASH_INIT_SIZE 128
-/* data structures (private to descriptor.c) **********************************/
+/* data structures (private to descriptor.c) **********************************/
typedef struct classref_hash_entry classref_hash_entry;
typedef struct descriptor_hash_entry descriptor_hash_entry;
struct descriptor_hash_entry {
descriptor_hash_entry *hashlink;
utf *desc;
- parseddesc parseddesc;
+ 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)
+
+
/****************************************************************************/
/* DEBUG HELPERS */
/****************************************************************************/
-#ifndef NDEBUG
-#define DESCRIPTOR_DEBUG
-#endif
+/*#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;
+}
-#ifdef DESCRIPTOR_DEBUG
-#define DESCRIPTOR_ASSERT(cond) assert(cond)
-#else
-#define DESCRIPTOR_ASSERT(cond)
-#endif
/* name_from_descriptor ********************************************************
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);
}
}
- *exceptionptr = new_classformaterror(c,"invalid descriptor");
+ exceptions_throw_classformaterror(c, "Invalid descriptor");
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
*******************************************************************************/
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 {
- DESCRIPTOR_ASSERT(utf_ptr[0] != '[' && utf_ptr[0] != 'L');
+ 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 */
- d->type = primitive_type_from_char(*utf_ptr);
- d->arraydim = 0;
- d->classref = NULL;
+ 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
u4 slot;
pool = DNEW(descriptor_pool);
- DESCRIPTOR_ASSERT(pool);
+ assert(pool);
pool->referer = referer;
pool->fieldcount = 0;
hashsize = CLASSREFHASH_INIT_SIZE;
pool->classrefhash.size = hashsize;
pool->classrefhash.entries = 0;
- pool->classrefhash.ptr = DMNEW(voidptr,hashsize);
+ pool->classrefhash.ptr = DMNEW(void*, hashsize);
for (slot=0; slot<hashsize; ++slot)
pool->classrefhash.ptr[slot] = NULL;
hashsize = DESCRIPTORHASH_INIT_SIZE;
pool->descriptorhash.size = hashsize;
pool->descriptorhash.entries = 0;
- pool->descriptorhash.ptr = DMNEW(voidptr,hashsize);
+ pool->descriptorhash.ptr = DMNEW(void*, hashsize);
for (slot=0; slot<hashsize; ++slot)
pool->descriptorhash.ptr[slot] = NULL;
return pool;
}
+
/* descriptor_pool_add_class ***************************************************
Add the given class reference to the pool
*******************************************************************************/
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 */
}
/* 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");
+
+ 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 = DNEW(classref_hash_entry);
c->name = name;
return true;
}
+
/* descriptor_pool_add *********************************************************
Check the given descriptor and add it to the pool
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)
+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) {
- *exceptionptr = new_classformaterror(pool->referer,"Missing ')' in method descriptor");
+ 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))
+ 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");
+ exceptions_throw_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
*******************************************************************************/
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; slot<pool->classrefhash.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;
- CLASSREF_INIT(*ref,pool->referer,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
*******************************************************************************/
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
{
u4 size;
- DESCRIPTOR_ASSERT(pool);
+ assert(pool);
- size = pool->fieldcount * sizeof(typedesc)
- + pool->methodcount * (sizeof(methoddesc) - sizeof(typedesc))
- + pool->paramcount * sizeof(typedesc);
+ /* 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 = 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
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,
- "Method descriptor used in field reference");
+ exceptions_throw_classformaterror(pool->referer,
+ "Method descriptor used in field reference");
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;
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] != '(') {
+ 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);
- 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->primitivetype = 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 (d->type == TYPE_LONG || d->type == TYPE_DOUBLE)
+ 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 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';
- 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->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
+
+ return true;
+}
+
+
/* descriptor_pool_get_parsed_descriptors **************************************
Return a pointer to the block of parsed descriptors
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
*******************************************************************************/
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
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,"<class=NULL>");
}
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->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);
}
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,"<m%d>",d->regoff);
+ }
+ else {
+ fprintf(file,"<r%d>",d->regoff);
+ }
+}
+
/* descriptor_debug_print_methoddesc *******************************************
Print the given methoddesc to the given stream
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("<NOPARAMS>",file);
fputc(')',file);
descriptor_debug_print_typedesc(file,&(d->returntype));
}
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);
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; slot<pool->classrefhash.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;
}
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;
}
}
}
else {
- while (size >= sizeof(voidptr)) {
- fprintf(file," %p\n",*((voidptr*)pos));
- pos += sizeof(voidptr);
- size -= sizeof(voidptr);
+ while (size >= sizeof(void*)) {
+ fprintf(file," %p\n",*((void**)pos));
+ pos += sizeof(void*);
+ size -= sizeof(void*);
}
}
}
fprintf(file,"==========================================================\n");
}
+#endif /* !defined(NDEBUG) */
/*
* These are local overrides for various environment variables in Emacs.