/*
 * classMethod.c
 * Dictionary of classes, methods and fields.
 *
 * Copyright (c) 1996 T. J. Wilkinson & Associates, London, UK.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * Written by Tim Wilkinson <tim@tjwassoc.demon.co.uk>, 1996.
 */

#define DBG(s)
#define	CDBG(s)
#define	MDBG(s)
#define	FDBG(s)
#define	LDBG(s)

#include "config.h"
#include "config-std.h"
#include "config-mem.h"
#include "gtypes.h"
#include "slots.h"
#include "access.h"
#include "object.h"
#include "classMethod.h"
#include "code.h"
#include "file.h"
#include "readClass.h"
#include "baseClasses.h"
#include "thread.h"
#include "itypes.h"
#include "errors.h"
#include "exception.h"
#include "md.h"
#include "external.h"
#include "lookup.h"
#include "support.h"
#include "gc.h"
#include "locks.h"
#include "md.h"

#define	CLASSHASHSZ		256	/* Must be a power of two */
static Hjava_lang_Class* classPool[CLASSHASHSZ];


extern gcFuncs gcClassObject;

extern Hjava_lang_Class* findClass(Hjava_lang_Class*, char*);
extern void verify2(Hjava_lang_Class*);
extern void verify3(Hjava_lang_Class*);

static Hjava_lang_Class* simpleLookupClass(Utf8Const*, Hjava_lang_ClassLoader*);
static Hjava_lang_Class* internalAddClass(Hjava_lang_Class*, Utf8Const*, int, int, Hjava_lang_ClassLoader*);

static void buildDispatchTable(Hjava_lang_Class*);
static void allocStaticFields(Hjava_lang_Class*);
static void resolveObjectFields(Hjava_lang_Class*);
static void resolveStaticFields(Hjava_lang_Class*);
static void resolveConstants(Hjava_lang_Class*);

#if !defined(ALIGNMENT_OF_SIZE)
#define	ALIGNMENT_OF_SIZE(S)	(S)
#endif

/*
 * Process all the stage of a classes initialisation.  We can provide
 * a state to aim for (so we don't have to do this all at once).  This
 * is called by various parts of the machine in order to load, link
 * and initialise the class.  Putting it all together here makes it a damn
 * sight easier to understand what's happening.
 */
void
processClass(Hjava_lang_Class* class, int tostate)
{
	int i;
	int idx;
	constants* pool;
	Method* meth;
	Hjava_lang_Class* super;
	Hjava_lang_Class* nclass;
	Field *fld;

	assert(tostate == CSTATE_LINKED || tostate == CSTATE_OK);

#define	SET_CLASS_STATE(S)	class->state = (S)
#define	DO_CLASS_STATE(S)	if ((S) > class->state && (S) <= tostate)

	/* Lock the class while we do this to avoid more than one thread
	 * doing this at once.
	 */
	lockMutex(class);

	DO_CLASS_STATE(CSTATE_LOADED) {

		/* Class not loaded - now would be a good time */
		if (findClass(class, class->name->data) == 0) {
			unlockMutex(class);
			throwException(ClassNotFoundException(class->name->data));
		}
	}

	DO_CLASS_STATE(CSTATE_PREPARED) {

		/* Check for circular dependent classes */
		if (class->state == CSTATE_DOING_PREPARE) {
			unlockMutex(class);
			throwException(ClassCircularityError);
		}

		SET_CLASS_STATE(CSTATE_DOING_PREPARE);

		/* Allocate any static space required by class and initialise
		 * the space with any constant values.
		 */
		allocStaticFields(class);

		/* Load and link the super class */
		if (class->superclass) {
			class->superclass = getClass((uintp)class->superclass, class);
			processClass(class->superclass, CSTATE_LINKED);
			CLASS_FSIZE(class) = CLASS_FSIZE(class->superclass);
		}

		/* Load all the implemented interfaces. */
		for (i = 0;  i < class->interface_len;  i++) {
			uintp iface = (uintp)class->interfaces[i];
			class->interfaces[i] = getClass(iface, class);
		}

		resolveObjectFields(class);
		resolveStaticFields(class);
		/* Build dispatch table, but not for interfaces */
		if ((class->accflags & ACC_INTERFACE) == 0) {
			buildDispatchTable(class);
		}

		SET_CLASS_STATE(CSTATE_PREPARED);
	}

	DO_CLASS_STATE(CSTATE_LINKED) {

		/* Okay, flag we're doing link */
		SET_CLASS_STATE(CSTATE_DOING_LINK);

		/* Second stage verification - check the class format is okay */
		verify2(class);

		/* Third stage verification - check the bytecode is okay */
		verify3(class);

		/* And note that it's done */
		SET_CLASS_STATE(CSTATE_LINKED);
	}

	DO_CLASS_STATE(CSTATE_OK) {

		/* If init is in progress return.  This must be the same
		 * thread because we lock the class when we come in here.
		 */
		if (class->state == CSTATE_DOING_INIT) {
			unlockMutex(class);
			return;
		}

		/* Initialise the constants */
		resolveConstants(class);

		SET_CLASS_STATE(CSTATE_DOING_INIT);

		super = class->superclass;
		if (super != NULL && super->state != CSTATE_OK) {
			processClass(super, CSTATE_OK);
		}

DBG(		printf("Initialising %s static %d\n", class->name->data,
			CLASS_SSIZE(class)); fflush(stdout);		)
		meth = findMethodLocal(class, init_name, void_signature);
		if (meth != NULL) {
			CALL_KAFFE_METHOD(meth, 0);
			/* Since we'll never run this again we might as well
			 * loose it now.
			 */
			METHOD_NATIVECODE(meth) = 0;
			meth->c.ncode.ncode_start = 0;
			meth->c.ncode.ncode_end = 0;
		}
		SET_CLASS_STATE(CSTATE_OK);
	}

	/* Unlock class now we're done */
	unlockMutex(class);
}

Hjava_lang_Class*
addClass(Hjava_lang_Class* cl, constIndex c, constIndex s, u2 flags, Hjava_lang_ClassLoader* loader)
{
	constants* pool;

	pool = CLASS_CONSTANTS(cl);

	/* Find the name of the class */
	if (pool->tags[c] != CONSTANT_Class) {
CDBG(		printf("addClass: not a class.\n");			)
		return (0);
	}
	return(internalAddClass(cl, WORD2UTF(pool->data[c]), flags, s, loader));
}

#if INTERN_UTF8CONSTS
static
int
hashClassName(Utf8Const *name)
{
	int len = (name->length+1) >> 1;  /* Number of shorts */
	uint16 *ptr = (uint16*) name->data;
	int hash = len;
	while (--len >= 0)
		hash = (hash << 1) ^ *ptr++;
	return hash;
}
#else
#define hashClassName(NAME) ((NAME)->hash)
#endif

/*
 * Take a prepared class and register it with the class pool.
 */
void
registerClass(Hjava_lang_Class* cl)
{
	Hjava_lang_Class** clp;
	uint32 hash;

	hash = hashClassName(cl->name) & (CLASSHASHSZ-1);

	/* All classes are entered in the global classPool.
	 * This is done, even for classes using a ClassLoader, following
	 * the prescription of the "Java Language Specification"
	 * (section 12.2:  Loading of Classes and Interfaces). */

	clp = &classPool[hash];
#ifdef DEBUG
	while (*clp != 0) {
		assert(! equalUtf8Consts (cl->name, (*clp)->name)
		       || loader != (*clp)->loader);
		clp = &(*clp)->next;
	}
#endif
	/* Add into list. */
	cl->next = *clp;
	*clp = cl; 
}

static
Hjava_lang_Class*
internalAddClass(Hjava_lang_Class* cl, Utf8Const* name, int flags, int su, Hjava_lang_ClassLoader* loader)
{
	cl->name = name;
	CLASS_METHODS(cl) = NULL;
	CLASS_NMETHODS(cl) = 0;
	cl->superclass = (Hjava_lang_Class*)(uintp)su;
	cl->msize = 0;
	CLASS_FIELDS(cl) = 0;
	CLASS_FSIZE(cl) = 0;
	cl->accflags = flags;
	cl->dtable = 0;
        cl->interfaces = 0;
	cl->interface_len = 0;
	cl->state = CSTATE_LOADED;
	cl->final = false;
	cl->loader = loader;

	registerClass(cl);

	return (cl);
}

Method*
addMethod(Hjava_lang_Class* c, method_info* m)
{
	constIndex nc;
	constIndex sc;
	Method* mt;
	constants* pool;
	Utf8Const* name;
	Utf8Const* signature;
	int ni;

	pool = CLASS_CONSTANTS (c);

	nc = m->name_index;
	if (pool->tags[nc] != CONSTANT_Utf8) {
MDBG(		printf("addMethod: no method name.\n");			)
		return (0);
	}
	sc = m->signature_index;
	if (pool->tags[sc] != CONSTANT_Utf8) {
MDBG(		printf("addMethod: no signature name.\n");		)
		return (0);
	}
	name = WORD2UTF (pool->data[nc]);
	signature = WORD2UTF (pool->data[sc]);

	if (equalUtf8Consts (name, final_name)
	    && equalUtf8Consts (signature, void_signature)) {
		c->final = true;
	}

#ifdef DEBUG
	/* Search down class for method name - don't allow duplicates */
	for (ni = CLASS_NMETHODS(c), mt = CLASS_METHODS(c); --ni >= 0; ) {
		assert(! equalUtf8Consts (name, mt->name)
		       || ! equalUtf8Consts (signature, mt->signature));
	}
#endif

MDBG(	printf("Adding method %s:%s%s (%x)\n", c->name->data, WORD2UTF(pool->data[nc])->data, WORD2UTF(pool->data[sc])->data, m->access_flags);	)

	mt = &c->methods[c->nmethods++];
	mt->name = name;
	mt->signature = signature;
	mt->class = c;
	mt->accflags = m->access_flags;
	mt->c.bcode.code = 0;
	mt->stacksz = 0;
	mt->localsz = 0;
	mt->exception_table = 0;

	return (mt);
}

Field*
addField(Hjava_lang_Class* c, field_info* f)
{
	constIndex nc;
	constIndex sc;
	Field* ft;
	constants* pool;
	int index;

	pool = CLASS_CONSTANTS (c);

	nc = f->name_index;
	if (pool->tags[nc] != CONSTANT_Utf8) {
FDBG(		printf("addField: no field name.\n");			)
		return (0);
	}

	--CLASS_FSIZE(c);
	if (f->access_flags & ACC_STATIC) {
		index = CLASS_NSFIELDS(c)++;
	}
	else {
		index = CLASS_FSIZE(c) + CLASS_NSFIELDS(c);
	}
	ft = &CLASS_FIELDS(c)[index];

FDBG(	printf("Adding field %s:%s\n", c->name, pool->data[nc].v.tstr);	)

	sc = f->signature_index;
	if (pool->tags[sc] != CONSTANT_Utf8) {
FDBG(		printf("addField: no signature name.\n");		)
		return (0);
	}
	ft->name = WORD2UTF (pool->data[nc]);
	FIELD_TYPE(ft) = (Hjava_lang_Class*)CLASS_CONST_UTF8(c, sc);
	ft->accflags = f->access_flags | FIELD_UNRESOLVED_FLAG;
	FIELD_CONSTIDX(ft) = 0;

	return (ft);
}

void
setFieldValue(Field* ft, u2 idx)
{
	/* Set value index */
	FIELD_CONSTIDX(ft) = idx;
	ft->accflags |= FIELD_CONSTANT_VALUE;
}

void
finishFields(Hjava_lang_Class *cl)
{
	Field tmp;
	Field* fld;
	int n;

	/* Reverse the instance fields, so they are in "proper" order. */
	fld = CLASS_IFIELDS(cl);
	n = CLASS_NIFIELDS(cl);
	while (n > 1) {
		tmp = fld[0];
		fld[0] = fld[n-1];
		fld[n-1] = tmp;
		fld++;
		n -= 2;
	}
}

void
addMethodCode(Method* m, Code* c)
{
	m->c.bcode.code = c->code;
	m->c.bcode.codelen = c->code_length;
	m->stacksz = c->max_stack;
	m->localsz = c->max_locals;
	m->exception_table = c->exception_table;
}

void
addInterfaces(Hjava_lang_Class* c, int inr, Hjava_lang_Class** inf)
{
	assert(inr > 0);

        c->interfaces = inf;
	c->interface_len = inr;
}

static char loadClassName[] = "loadClass";
static char loadClassSig[] = "(Ljava/lang/String;Z)Ljava/lang/Class;";

/*
 * Lookup a named class, loading it if necessary.
 * The name is as used in class files, e.g. "java/lang/String".
 */
Hjava_lang_Class*
loadClass(Utf8Const* name, Hjava_lang_ClassLoader* loader)
{
	Hjava_lang_Class* class;

	class = simpleLookupClass(name, loader);
	if (class != NULL) {
		return (class);
	}

	/* Failed to find class, so must now load it */

	if (loader != NULL) {
		Hjava_lang_String* str;

LDBG(		printf("classLoader: loading %s\n", name->data); )
		str = makeReplaceJavaStringFromUtf8(name->data, name->length, '/', '.');
		class = (Hjava_lang_Class*)do_execute_java_method (NULL, (Hjava_lang_Object*)loader, loadClassName, loadClassSig, 0, false, str, true);
LDBG(		printf("classLoader: done\n");			)
		if (class == NULL) {
			throwException(ClassNotFoundException(name->data));
		}
	}
	else {
		class = (struct Hjava_lang_Class*)newObject(&ClassClass);
		class->name = name;
		class->state = CSTATE_UNLOADED;
	}

	processClass(class, CSTATE_LINKED);
	return (class);
}

void
loadStaticClass(Hjava_lang_Class* class, char* name)
{
	gc_attach(class, sizeof(Hjava_lang_Class), &gcClassObject);
	class->name = makeUtf8Const(name, -1);
	class->state = CSTATE_UNLOADED;
	processClass(class, CSTATE_LINKED);
        class->head.dtable = ClassClass.dtable;
}

Hjava_lang_Class*
lookupClass(char* name)
{
	Hjava_lang_Class* class;

	class = loadClass(makeUtf8Const (name, strlen (name)), NULL);
	if (class->state != CSTATE_OK) {
		processClass(class, CSTATE_OK);
	}
	return (class);
}

static
void
resolveObjectFields(Hjava_lang_Class* class)
{
	int fsize;
	int align;
	char* sig;
	Field* fld;
	int n;
	int offset;
	int lalign;

	/* Find start of new fields in this object.  If start is zero, we must
	 * allow for the object headers.
	 */
	offset = CLASS_FSIZE(class);
	if (offset == 0) {
		offset = sizeof(Hjava_lang_Object);
	}

	/* Find the largest alignment in this class */
	align = 1;
	fld = CLASS_IFIELDS(class);
	n = CLASS_NIFIELDS(class);
	for (; --n >= 0; fld++) {
		if (FIELD_RESOLVED(fld)) {
			fsize = FIELD_SIZE(fld);
		}
		else {
			sig = ((Utf8Const*)FIELD_TYPE(fld))->data;
			if (sig[0] == 'L' || sig[0] == '[') {
				fsize = PTR_TYPE_SIZE;
			}
			else {
				FIELD_TYPE(fld) = classFromSig(&sig, class->loader);
				fsize = TYPE_PRIM_SIZE(FIELD_TYPE(fld));
				fld->accflags &= ~FIELD_UNRESOLVED_FLAG;
			}
			FIELD_SIZE(fld) = fsize;
		}

		/* Work out alignment for this size entity */
		fsize = ALIGNMENT_OF_SIZE(fsize);

		/* If field is bigger than biggest alignment, change
		 * biggest alignment
		 */
		if (fsize > align) {
			align = fsize;
		}
	}

	/* Align start of this class's data */
	offset = ((offset + align - 1) / align) * align;

	/* Now work out where to put each field */
	fld = CLASS_IFIELDS(class);
	n = CLASS_NIFIELDS(class);
	for (; --n >= 0; fld++) {
		if (FIELD_RESOLVED(fld)) {
			fsize = FIELD_SIZE(fld);
		}
		else {
			/* Unresolved fields must be object references */
			fsize = PTR_TYPE_SIZE;
		}
		/* Align field */
		align = ALIGNMENT_OF_SIZE(fsize);
		offset = ((offset + align - 1) / align) * align;
		FIELD_OFFSET(fld) = offset;
		offset += fsize;
	}

	CLASS_FSIZE(class) = offset;
}

/*
 * Allocate the space for the static class data.
 */
static
void
allocStaticFields(Hjava_lang_Class* class)
{
	int fsize;
	int align;
	char* sig;
	uint8* mem;
	int offset;
	int idx;
	int n;
	Field* fld;
	constants* pool;

	/* No static fields */
	if (CLASS_NSFIELDS(class) == 0) {
		return;
	}

	/* Calculate size and position of static data */
	offset = 0;
	n = CLASS_NSFIELDS(class);
	fld = CLASS_SFIELDS(class);
	for (; --n >= 0; fld++) {
		sig = ((Utf8Const*)FIELD_TYPE(fld))->data;
		if (sig[0] == 'L' || sig[0] == '[') {
			fsize = PTR_TYPE_SIZE;
		}
		else {
			assert(!FIELD_RESOLVED(fld));
			FIELD_TYPE(fld) = classFromSig(&sig, class->loader);
			fsize = TYPE_PRIM_SIZE(FIELD_TYPE(fld));
			fld->accflags &= ~FIELD_UNRESOLVED_FLAG;
		}
		/* Align field offset */
		if (fsize < 4) {
			fsize = 4;
		}
		align = fsize;
		offset = ((offset + align - 1) / align) * align;
		FIELD_SIZE(fld) = offset;
		offset += fsize;
	}

	/* Allocate memory required */
	mem = gc_malloc(offset, &gcStaticData);

	/* Rewalk the fields, pointing them at the relevant memory and/or
	 * setting any constant values.
	 */
	fld = CLASS_SFIELDS(class);
	n = CLASS_NSFIELDS(class);
	for (; --n >= 0; fld++) {
		offset = FIELD_SIZE(fld);
		FIELD_SIZE(fld) = FIELD_CONSTIDX(fld);	/* Keep idx in size */
		FIELD_ADDRESS(fld) = mem + offset;
	}
}

static
void
resolveStaticFields(Hjava_lang_Class* class)
{
	uint8* mem;
	constants* pool;
	Field* fld;
	int idx;
	int n;

	pool = CLASS_CONSTANTS(class);
	fld = CLASS_SFIELDS(class);
	n = CLASS_NSFIELDS(class);
	for (; --n >= 0; fld++) {
		if ((fld->accflags & FIELD_CONSTANT_VALUE) != 0) {

			mem = FIELD_ADDRESS(fld);
			idx = FIELD_SIZE(fld);

			switch (CONST_TAG(idx, pool)) {
			case CONSTANT_Integer:
			case CONSTANT_Float:
				*(jint*)mem = CLASS_CONST_INT(class, idx);
				FIELD_SIZE(fld) = 4; /* ??? */
				break;

			case CONSTANT_Long:
			case CONSTANT_Double:
				*(jlong*)mem = CLASS_CONST_LONG(class, idx);
				FIELD_SIZE(fld) = 8; /* ??? */
				break;

			case CONSTANT_String:
				pool->data[idx] = (ConstSlot)Utf8Const2JavaString(WORD2UTF(pool->data[idx]));
				pool->tags[idx] = CONSTANT_ResolvedString;
				/* ... fall through ... */
			case CONSTANT_ResolvedString:
				*(jref*)mem = (jref)CLASS_CONST_DATA(class, idx);
				FIELD_SIZE(fld) = PTR_TYPE_SIZE;
				break;
			}
		}
	}
}

static
void
buildDispatchTable(Hjava_lang_Class* class)
{
	Method* meth;
	void** mtab;
	int i;
	int ntramps = 0;
#if defined(TRANSLATOR) && defined(HAVE_TRAMPOLINE)
	methodTrampoline* tramp;
#endif

	if (class->superclass != NULL) {
		/* This may not be the best place to do this but at least
		   it is centralized.  */
		class->subclass_next = class->superclass->subclass_next;
		class->superclass->subclass_next = class;

		class->msize = class->superclass->msize;
	}
	else {
		class->msize = 0;
	}

	meth = CLASS_METHODS(class);
	i = CLASS_NMETHODS(class);
	for (; --i >= 0; meth++) {
		Hjava_lang_Class* super = class->superclass;
		if (!METHOD_TRANSLATED(meth)) {
			ntramps++;
		}
		if ((meth->accflags & ACC_STATIC)
		    || equalUtf8Consts(meth->name, constructor_name)) {
			meth->idx = -1;
			continue;
		}
		/* Search superclasses for equivalent method name.
		 * If found extract its index nr.
		 */
		for (; super != NULL;  super = super->superclass) {
			int j = CLASS_NMETHODS(super);
			Method* mt = CLASS_METHODS(super);
			for (; --j >= 0;  ++mt) {
				if (equalUtf8Consts (mt->name, meth->name)
				    && equalUtf8Consts (mt->signature,
							meth->signature)) {
					meth->idx = mt->idx;
					goto foundmatch;
				}
			}
		}
		/* No match found so allocate a new index number */
		meth->idx = class->msize++;
		foundmatch:;
	}

#if defined(TRANSLATOR) && defined(HAVE_TRAMPOLINE)
	/* Allocate the dispatch table and this class' trampolines all in
	   one block of memory.  This is primarily done for GC reasons in
	   that I didn't want to add another slot on class just for holding
	   the trampolines, but it also works out for space reasons.  */
	class->dtable = (dispatchTable*)gc_malloc(sizeof(dispatchTable) + class->msize * sizeof(void*) + ntramps * sizeof(methodTrampoline), &gcDispatchTable);
	tramp = (methodTrampoline*) &class->dtable->method[class->msize];
#else
	class->dtable = (dispatchTable*)gc_malloc(sizeof(dispatchTable) + (class->msize * sizeof(void*)), &gcDispatchTable);
#endif

	class->dtable->class = class;
	mtab = class->dtable->method;

	/* Install inherited methods into dispatch table. */
	if (class->superclass != NULL) {
		Method** super_mtab = (Method**)class->superclass->dtable->method;
		for (i = 0; i < class->superclass->msize; i++) {
			mtab[i] = super_mtab[i];
		}
	}

	meth = CLASS_METHODS(class);
	i = CLASS_NMETHODS(class);
#if defined(TRANSLATOR) && defined(HAVE_TRAMPOLINE)
	for (; --i >= 0; meth++) {
		if (!METHOD_TRANSLATED(meth)) {
			FILL_IN_TRAMPOLINE(tramp, meth);
			METHOD_NATIVECODE(meth) = (nativecode*)tramp;
			tramp++;
		}
		if (meth->idx >= 0) {
			mtab[meth->idx] = METHOD_NATIVECODE(meth);
		}
	}
	FLUSH_DCACHE(class->dtable, tramp);
#else
	for (;  --i >= 0; meth++) {
		if (meth->idx >= 0) {
			mtab[meth->idx] = meth;
		}
	}
#endif

	/* Check for undefined abstract methods if class is not abstract.
	 * See "Java Language Specification" (1996) section 12.3.2. */
	if ((class->accflags & ACC_ABSTRACT) == 0) {
		for (i = class->msize - 1; i >= 0; i--) {
			if (mtab[i] == NULL) {
				throwException(AbstractMethodError);
			}
		}
	}
}

#if defined(TRANSLATOR) && defined(HAVE_TRAMPOLINE)

/*
 * Fixup a trampoline, replacing the trampoline with the real code.
 */
static
void
fixupDispatchTable(Hjava_lang_Class *c, nativecode *ocode, nativecode *ncode, int idx)
{
	if (c->dtable->method[idx] == ocode) {
		c->dtable->method[idx] = ncode;
		for (c = c->subclass_head; c; c = c->subclass_next) {
			fixupDispatchTable(c, ocode, ncode, idx);
		}
	}
}

/*
 * Trampolines come in here - do the translation and replace the trampoline.
 */
nativecode*
fixupTrampoline FIXUP_TRAMPOLINE_DECL
{
	Method* meth;
	nativecode* ocode;

	FIXUP_TRAMPOLINE_INIT;

	/* If this class needs initializing, do it now.  */
	if (meth->class->state != CSTATE_OK) {
		processClass(meth->class, CSTATE_OK);
	}

	/* Generate code on demand.  */
	if (!METHOD_TRANSLATED(meth)) {
		ocode = METHOD_NATIVECODE(meth);
		translate(meth);

		/* Update the dtable entries for all classes if this isn't a
	   	   static method.  */
		if (meth->idx >= 0) {
			fixupDispatchTable(meth->class, ocode, METHOD_NATIVECODE(meth), meth->idx);
		}
	}

	return (METHOD_NATIVECODE(meth));
}
#endif

/*
 * Initialise the constants.
 * First we make sure all the constant strings are converted to java strings.
 */
static
void
resolveConstants(Hjava_lang_Class* class)
{
	Field* fld;
	int n;
	int idx;
	constants* pool;

	assert(class->state == CSTATE_LINKED);
	class->state = CSTATE_DOING_CONSTINIT;

	/* Scan constant pool and convert any constant strings into true
	 * java strings.
	 */
	pool = CLASS_CONSTANTS (class);
	for (idx = 0; idx < pool->size; idx++) {
		if (pool->tags[idx] == CONSTANT_String) {
			pool->data[idx] = (ConstSlot)Utf8Const2JavaString(WORD2UTF(pool->data[idx]));
			pool->tags[idx] = CONSTANT_ResolvedString;
		}
		else if (pool->tags[idx] == CONSTANT_Class) {
			getClass(idx, class);
		}
	}

	class->state = CSTATE_CONSTINIT;
}

static
Hjava_lang_Class*
simpleLookupClass(Utf8Const* name, Hjava_lang_ClassLoader* loader)
{
	Hjava_lang_Class* clp;

	for (clp = classPool[hashClassName(name) & (CLASSHASHSZ-1)]; clp != 0 && !(equalUtf8Consts(name, clp->name) && loader == clp->loader); clp = clp->next)
		;
	return (clp);
}

/*
 * Lookup a named field.
 */
Field*
lookupClassField(Hjava_lang_Class* clp, Utf8Const* name, bool isStatic)
{
	Field* fptr;
	int n;

	/* Search down class for field name */
	if (isStatic) {
		fptr = CLASS_SFIELDS(clp);
		n = CLASS_NSFIELDS(clp);
	}
	else {
		fptr = CLASS_IFIELDS(clp);
		n = CLASS_NIFIELDS(clp);
	}
	while (--n >= 0) {
		if (equalUtf8Consts (name, fptr->name)) {
			if (!FIELD_RESOLVED(fptr)) {
				char* sig;
				sig = ((Utf8Const*)FIELD_TYPE(fptr))->data;
				FIELD_TYPE(fptr) = classFromSig(&sig, clp->loader);
				fptr->accflags &= ~FIELD_UNRESOLVED_FLAG;
			}
			return (fptr);
		}
		fptr++;
	}
FDBG(	printf("Class:field lookup failed %s:%s\n", c, f);		)
	return (0);
}

/*
 * Determine the number of arguments and return values from the
 * method signature.
 */
void
countInsAndOuts(char* str, short* ins, short* outs, char* outtype)
{
	*ins = sizeofSig(&str, false);
	*outtype = str[0];
	*outs = sizeofSig(&str, false);
}

/*
 * Calculate size of data item based on signature.
 */
int
sizeofSig(char** strp, bool want_wide_refs)
{
	int count;
	int c;

	count = 0;
	for (;;) {
		c = sizeofSigItem(strp, want_wide_refs);
		if (c == -1) {
			return (count);
		}
		count += c;
	}
}

/*
 * Calculate size (in words) of a signature item.
 */
int
sizeofSigItem(char** strp, bool want_wide_refs)
{
	int count;
	char* str;

	for (str = *strp; ; str++) {
		switch (*str) {
		case '(':
			continue;
		case 0:
		case ')':
			count = -1;
			break;
		case 'V':
			count = 0;
			break;
		case 'I':
		case 'Z':
		case 'S':
		case 'B':
		case 'C':
		case 'F':
			count = 1;
			break;
		case 'D':
		case 'J':
			count = 2;
			break;
		case '[':
			count = want_wide_refs ? sizeof(void*) / sizeof(int32) : 1;
			arrayofarray:
			str++;
			if (*str == 'L') {
				while (*str != ';') {
					str++;
				}
			}
			else if (*str == '[') {
				goto arrayofarray;
			}
			break;
		case 'L':
			count = want_wide_refs ? sizeof(void*) / sizeof(int32) : 1;
			/* Skip to end of reference */
			while (*str != ';') {
				str++;
			}
			break;
		default:
			ABORT();
		}

		*strp = str + 1;
		return (count);
	}
}

/*
 * Find (or create) an array class with component type C.
 */
Hjava_lang_Class*
lookupArray(Hjava_lang_Class* c)
{
	Utf8Const *arr_name;
	char sig[CLASSMAXSIG];  /* FIXME! unchecked fixed buffer! */
	Hjava_lang_Class* arr_class;

	/* Build signature for array type */
	if (CLASS_IS_PRIMITIVE (c)) {
		arr_class = CLASS_ARRAY_CACHE(c);
		if (arr_class) {
			return (arr_class);
		}
		sprintf (sig, "[%c", CLASS_PRIM_SIG(c));
	}
	else {
		char* cname = CLASS_CNAME (c);
		sprintf (sig, cname[0] == '[' ? "[%s" : "[L%s;", cname);
	}
	arr_name = makeUtf8Const (sig, -1);
	arr_class = simpleLookupClass(arr_name, c->loader);
	if (arr_class == NULL) {
		arr_class = (Hjava_lang_Class*)newObject(&ClassClass);
		arr_class = internalAddClass(arr_class, arr_name, 0, 0, c->loader);
		arr_class->superclass = &ObjectClass;
		buildDispatchTable(arr_class);
		CLASS_ELEMENT_TYPE(arr_class) = c;
		arr_class->state = CSTATE_OK;
	}
#if 0 /* !INTERN_UTF8CONSTS */
	else {
		free (arr_name);
	}
#endif
	if (CLASS_IS_PRIMITIVE (c)) {
		CLASS_ARRAY_CACHE(c) = arr_class;
	}
	return (arr_class);
}

#if defined(TRANSLATOR)
/*
 * Find method containing pc.
 */
Method*
findMethodFromPC(uintp pc)
{
	Hjava_lang_Class *class;
	Method* ptr;
	int ipool, imeth;

	for (ipool = CLASSHASHSZ;  --ipool >= 0; ) {
		for (class = classPool[ipool];  class != NULL; ) {
			imeth = CLASS_NMETHODS(class);
			ptr = CLASS_METHODS(class);
			for (; --imeth >= 0;  ptr++) {
				if (pc >= (uintp)METHOD_NATIVECODE(ptr)
				    && pc < (uintp)ptr->c.ncode.ncode_end) {
					return (ptr);
				}
			}
			class = class->next;
		}
	}
	return (NULL);
}
#endif
